@typeberry/lib 0.5.10-6cb1bd5 → 0.5.10-7338c21
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/package.json +1 -1
- package/packages/core/codec/encoder.d.ts +1 -1
- package/packages/core/codec/encoder.d.ts.map +1 -1
- package/packages/core/codec/encoder.js +3 -2
- package/packages/core/pvm-interface/pvm.d.ts +2 -0
- package/packages/core/pvm-interface/pvm.d.ts.map +1 -1
- package/packages/jam/block/work-package.d.ts +7 -7
- package/packages/jam/block/work-package.d.ts.map +1 -1
- package/packages/jam/block/work-package.js +12 -12
- package/packages/jam/executor/pvm-executor.d.ts +9 -2
- package/packages/jam/executor/pvm-executor.d.ts.map +1 -1
- package/packages/jam/executor/pvm-executor.js +15 -0
- package/packages/jam/in-core/externalities/refine.d.ts +18 -8
- package/packages/jam/in-core/externalities/refine.d.ts.map +1 -1
- package/packages/jam/in-core/externalities/refine.js +86 -7
- package/packages/jam/in-core/externalities/refine.test.js +167 -2
- package/packages/jam/in-core/in-core.d.ts +7 -22
- package/packages/jam/in-core/in-core.d.ts.map +1 -1
- package/packages/jam/in-core/in-core.js +16 -186
- package/packages/jam/in-core/in-core.test.js +47 -15
- package/packages/jam/in-core/is-authorized.d.ts +33 -0
- package/packages/jam/in-core/is-authorized.d.ts.map +1 -0
- package/packages/jam/in-core/is-authorized.js +72 -0
- package/packages/jam/in-core/is-authorized.test.d.ts +2 -0
- package/packages/jam/in-core/is-authorized.test.d.ts.map +1 -0
- package/packages/jam/in-core/is-authorized.test.js +125 -0
- package/packages/jam/in-core/refine.d.ts +34 -0
- package/packages/jam/in-core/refine.d.ts.map +1 -0
- package/packages/jam/in-core/refine.js +176 -0
- package/packages/jam/in-core/refine.test.d.ts +2 -0
- package/packages/jam/in-core/refine.test.d.ts.map +1 -0
- package/packages/jam/in-core/refine.test.js +6 -0
- package/packages/jam/jam-host-calls/accumulate/bless.js +9 -9
- package/packages/jam/jam-host-calls/externalities/partial-state.d.ts +1 -1
- package/packages/jam/jam-host-calls/externalities/refine-externalities.d.ts +1 -1
- package/packages/jam/jam-host-calls/externalities/refine-externalities.d.ts.map +1 -1
- package/packages/jam/jam-host-calls/general/fetch.d.ts +164 -103
- package/packages/jam/jam-host-calls/general/fetch.d.ts.map +1 -1
- package/packages/jam/jam-host-calls/general/fetch.js +117 -23
- package/packages/jam/jam-host-calls/general/fetch.test.js +100 -66
- package/packages/jam/jamnp-s/protocol/ce-133-work-package-submission.d.ts +2 -2
- package/packages/jam/transition/accumulate/accumulate.js +2 -2
- package/packages/jam/transition/accumulate/accumulation-result-merge-utils.js +48 -39
- package/packages/jam/transition/externalities/accumulate-externalities.d.ts +2 -2
- package/packages/jam/transition/externalities/accumulate-externalities.d.ts.map +1 -1
- package/packages/jam/transition/externalities/accumulate-externalities.js +20 -7
- package/packages/jam/transition/externalities/accumulate-externalities.test.js +74 -4
- package/packages/jam/transition/externalities/accumulate-fetch-externalities.d.ts +19 -0
- package/packages/jam/transition/externalities/accumulate-fetch-externalities.d.ts.map +1 -0
- package/packages/jam/transition/externalities/accumulate-fetch-externalities.js +45 -0
- package/packages/jam/transition/externalities/accumulate-fetch-externalities.test.d.ts +2 -0
- package/packages/jam/transition/externalities/accumulate-fetch-externalities.test.d.ts.map +1 -0
- package/packages/jam/transition/externalities/accumulate-fetch-externalities.test.js +192 -0
- package/packages/jam/transition/externalities/fetch-externalities.d.ts +3 -39
- package/packages/jam/transition/externalities/fetch-externalities.d.ts.map +1 -1
- package/packages/jam/transition/externalities/fetch-externalities.js +2 -88
- package/packages/jam/transition/externalities/index.d.ts +3 -0
- package/packages/jam/transition/externalities/index.d.ts.map +1 -1
- package/packages/jam/transition/externalities/index.js +3 -0
- package/packages/jam/transition/externalities/is-authorized-fetch-externalities.d.ts +22 -0
- package/packages/jam/transition/externalities/is-authorized-fetch-externalities.d.ts.map +1 -0
- package/packages/jam/transition/externalities/is-authorized-fetch-externalities.js +41 -0
- package/packages/jam/transition/externalities/refine-fetch-externalities.d.ts +23 -0
- package/packages/jam/transition/externalities/refine-fetch-externalities.d.ts.map +1 -0
- package/packages/jam/transition/externalities/refine-fetch-externalities.js +56 -0
- package/packages/jam/transition/externalities/refine-fetch-externalities.test.d.ts +2 -0
- package/packages/jam/transition/externalities/refine-fetch-externalities.test.d.ts.map +1 -0
- package/packages/jam/transition/externalities/refine-fetch-externalities.test.js +32 -0
- package/packages/jam/transition/externalities/fetch-externalities.test.d.ts +0 -2
- package/packages/jam/transition/externalities/fetch-externalities.test.d.ts.map +0 -1
- package/packages/jam/transition/externalities/fetch-externalities.test.js +0 -254
|
@@ -3,12 +3,15 @@ import { describe, it } from "node:test";
|
|
|
3
3
|
import { MAX_NUMBER_OF_EXPORTS_WP, SEGMENT_BYTES, tryAsServiceGas, tryAsServiceId, tryAsTimeSlot, } from "#@typeberry/block";
|
|
4
4
|
import { Bytes, BytesBlob } from "#@typeberry/bytes";
|
|
5
5
|
import { HashDictionary } from "#@typeberry/collections";
|
|
6
|
-
import { tinyChainSpec } from "#@typeberry/config";
|
|
6
|
+
import { PvmBackend, tinyChainSpec } from "#@typeberry/config";
|
|
7
7
|
import { HASH_SIZE } from "#@typeberry/hash";
|
|
8
|
-
import { SegmentExportError } from "#@typeberry/jam-host-calls";
|
|
8
|
+
import { SegmentExportError, tryAsMachineId, tryAsProgramCounter } from "#@typeberry/jam-host-calls";
|
|
9
9
|
import { tryAsU32, tryAsU64 } from "#@typeberry/numbers";
|
|
10
|
+
import { HostCallRegisters } from "#@typeberry/pvm-host-calls";
|
|
11
|
+
import { NO_OF_REGISTERS, REGISTER_BYTE_SIZE, Status, tryAsBigGas } from "#@typeberry/pvm-interface";
|
|
10
12
|
import { InMemoryService, InMemoryState, PreimageItem, ServiceAccountInfo } from "#@typeberry/state";
|
|
11
13
|
import { RefineExternalitiesImpl } from "./refine.js";
|
|
14
|
+
const MINIMAL_PROGRAM = new Uint8Array([0, 1, 1, 0, 0x00]);
|
|
12
15
|
function createSegment(byte = 0xab) {
|
|
13
16
|
return Bytes.fill(SEGMENT_BYTES, byte);
|
|
14
17
|
}
|
|
@@ -59,9 +62,13 @@ function createExt(overrides = {}) {
|
|
|
59
62
|
currentServiceId: tryAsServiceId(42),
|
|
60
63
|
lookupState: overrides.lookupState ?? defaultState,
|
|
61
64
|
exportOffset: overrides.exportOffset ?? 0,
|
|
65
|
+
pvmBackend: PvmBackend.BuiltIn,
|
|
62
66
|
...overrides,
|
|
63
67
|
});
|
|
64
68
|
}
|
|
69
|
+
function emptyRegisters() {
|
|
70
|
+
return new HostCallRegisters(new Uint8Array(NO_OF_REGISTERS * REGISTER_BYTE_SIZE));
|
|
71
|
+
}
|
|
65
72
|
describe("RefineExternalitiesImpl", () => {
|
|
66
73
|
describe("historicalLookup", () => {
|
|
67
74
|
const PREIMAGE_HASH = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
|
@@ -160,4 +167,162 @@ describe("RefineExternalitiesImpl", () => {
|
|
|
160
167
|
assert.deepStrictEqual(exported[0].raw.subarray(0, 5), new Uint8Array([1, 2, 3, 4, 5]));
|
|
161
168
|
});
|
|
162
169
|
});
|
|
170
|
+
describe("machineInit", () => {
|
|
171
|
+
it("should create a new inner PVM and return a machine ID", async () => {
|
|
172
|
+
const ext = createExt();
|
|
173
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
174
|
+
const pc = tryAsProgramCounter(0);
|
|
175
|
+
const result = await ext.machineInit(code, pc);
|
|
176
|
+
assert.strictEqual(result.isOk, true);
|
|
177
|
+
assert.strictEqual(result.ok, tryAsMachineId(0));
|
|
178
|
+
});
|
|
179
|
+
it("should assign sequential machine IDs", async () => {
|
|
180
|
+
const ext = createExt();
|
|
181
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
182
|
+
const pc = tryAsProgramCounter(0);
|
|
183
|
+
const r1 = await ext.machineInit(code, pc);
|
|
184
|
+
const r2 = await ext.machineInit(code, pc);
|
|
185
|
+
const r3 = await ext.machineInit(code, pc);
|
|
186
|
+
assert.strictEqual(r1.isOk, true);
|
|
187
|
+
assert.strictEqual(r1.ok, tryAsMachineId(0));
|
|
188
|
+
assert.strictEqual(r2.isOk, true);
|
|
189
|
+
assert.strictEqual(r2.ok, tryAsMachineId(1));
|
|
190
|
+
assert.strictEqual(r3.isOk, true);
|
|
191
|
+
assert.strictEqual(r3.ok, tryAsMachineId(2));
|
|
192
|
+
});
|
|
193
|
+
it("should return error for invalid program blob", async () => {
|
|
194
|
+
const ext = createExt();
|
|
195
|
+
const invalidCode = BytesBlob.blobFrom(new Uint8Array([0xff, 0xff, 0xff]));
|
|
196
|
+
const pc = tryAsProgramCounter(0);
|
|
197
|
+
const result = await ext.machineInit(invalidCode, pc);
|
|
198
|
+
assert.strictEqual(result.isError, true);
|
|
199
|
+
});
|
|
200
|
+
it("should return error for empty program blob", async () => {
|
|
201
|
+
const ext = createExt();
|
|
202
|
+
const emptyCode = BytesBlob.blobFrom(new Uint8Array([]));
|
|
203
|
+
const pc = tryAsProgramCounter(0);
|
|
204
|
+
const result = await ext.machineInit(emptyCode, pc);
|
|
205
|
+
assert.strictEqual(result.isError, true);
|
|
206
|
+
});
|
|
207
|
+
it("should accept a non-zero program counter", async () => {
|
|
208
|
+
const ext = createExt();
|
|
209
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
210
|
+
const pc = tryAsProgramCounter(1);
|
|
211
|
+
const result = await ext.machineInit(code, pc);
|
|
212
|
+
assert.strictEqual(result.isOk, true);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe("machineExpunge", () => {
|
|
216
|
+
it("should remove machine and return its program counter (0)", async () => {
|
|
217
|
+
const ext = createExt();
|
|
218
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
219
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(0));
|
|
220
|
+
assert.strictEqual(initResult.isOk, true);
|
|
221
|
+
const machineId = initResult.ok;
|
|
222
|
+
const result = await ext.machineExpunge(machineId);
|
|
223
|
+
assert.strictEqual(result.isOk, true);
|
|
224
|
+
// PC should be 0 since we initialized with PC=0
|
|
225
|
+
assert.strictEqual(result.ok, tryAsProgramCounter(0));
|
|
226
|
+
});
|
|
227
|
+
it("should remove machine and return its program counter (10)", async () => {
|
|
228
|
+
const ext = createExt();
|
|
229
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
230
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(10));
|
|
231
|
+
assert.strictEqual(initResult.isOk, true);
|
|
232
|
+
const machineId = initResult.ok;
|
|
233
|
+
const result = await ext.machineExpunge(machineId);
|
|
234
|
+
assert.strictEqual(result.isOk, true);
|
|
235
|
+
// PC should be 10 since we initialized with PC=10
|
|
236
|
+
assert.strictEqual(result.ok, tryAsProgramCounter(10));
|
|
237
|
+
});
|
|
238
|
+
it("should return NoMachineError for non-existent machine", async () => {
|
|
239
|
+
const ext = createExt();
|
|
240
|
+
const result = await ext.machineExpunge(tryAsMachineId(999));
|
|
241
|
+
assert.strictEqual(result.isError, true);
|
|
242
|
+
});
|
|
243
|
+
it("should not allow double expunge", async () => {
|
|
244
|
+
const ext = createExt();
|
|
245
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
246
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(0));
|
|
247
|
+
assert.strictEqual(initResult.isOk, true);
|
|
248
|
+
const machineId = initResult.ok;
|
|
249
|
+
const r1 = await ext.machineExpunge(machineId);
|
|
250
|
+
assert.strictEqual(r1.isOk, true);
|
|
251
|
+
const r2 = await ext.machineExpunge(machineId);
|
|
252
|
+
assert.strictEqual(r2.isError, true);
|
|
253
|
+
});
|
|
254
|
+
it("should remove exact machine from multiple and return its program counter (10)", async () => {
|
|
255
|
+
const ext = createExt();
|
|
256
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
257
|
+
await ext.machineInit(code, tryAsProgramCounter(0));
|
|
258
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(10));
|
|
259
|
+
await ext.machineInit(code, tryAsProgramCounter(20));
|
|
260
|
+
assert.strictEqual(initResult.isOk, true);
|
|
261
|
+
const machineId = initResult.ok;
|
|
262
|
+
const result = await ext.machineExpunge(machineId);
|
|
263
|
+
assert.strictEqual(result.isOk, true);
|
|
264
|
+
// PC should be 10 since we initialized with PC=10
|
|
265
|
+
assert.strictEqual(result.ok, tryAsProgramCounter(10));
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
describe("machineInvoke", () => {
|
|
269
|
+
it("should return NoMachineError for non-existent machine", async () => {
|
|
270
|
+
const ext = createExt();
|
|
271
|
+
const regs = emptyRegisters();
|
|
272
|
+
const result = await ext.machineInvoke(tryAsMachineId(999), tryAsBigGas(1000n), regs);
|
|
273
|
+
assert.strictEqual(result.isError, true);
|
|
274
|
+
});
|
|
275
|
+
it("should execute inner PVM and return PANIC for TRAP instruction", async () => {
|
|
276
|
+
const ext = createExt();
|
|
277
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
278
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(0));
|
|
279
|
+
assert.strictEqual(initResult.isOk, true);
|
|
280
|
+
const machineId = initResult.ok;
|
|
281
|
+
const regs = emptyRegisters();
|
|
282
|
+
const result = await ext.machineInvoke(machineId, tryAsBigGas(1000n), regs);
|
|
283
|
+
assert.strictEqual(result.isOk, true);
|
|
284
|
+
assert.strictEqual(result.ok.result.status, Status.PANIC);
|
|
285
|
+
});
|
|
286
|
+
it("should return OOG when gas is exhausted", async () => {
|
|
287
|
+
const ext = createExt();
|
|
288
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
289
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(0));
|
|
290
|
+
assert.strictEqual(initResult.isOk, true);
|
|
291
|
+
const machineId = initResult.ok;
|
|
292
|
+
const regs = emptyRegisters();
|
|
293
|
+
// With 0 gas, should immediately OOG
|
|
294
|
+
const result = await ext.machineInvoke(machineId, tryAsBigGas(0n), regs);
|
|
295
|
+
assert.strictEqual(result.isOk, true);
|
|
296
|
+
assert.strictEqual(result.ok.result.status, Status.OOG);
|
|
297
|
+
});
|
|
298
|
+
it("should pass registers to inner PVM and return them back", async () => {
|
|
299
|
+
const ext = createExt();
|
|
300
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
301
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(0));
|
|
302
|
+
assert.strictEqual(initResult.isOk, true);
|
|
303
|
+
const machineId = initResult.ok;
|
|
304
|
+
const regs = emptyRegisters();
|
|
305
|
+
regs.set(0, tryAsU64(0xdeadbeefn));
|
|
306
|
+
regs.set(5, tryAsU64(0xcafebaben));
|
|
307
|
+
const result = await ext.machineInvoke(machineId, tryAsBigGas(1000n), regs);
|
|
308
|
+
assert.strictEqual(result.isOk, true);
|
|
309
|
+
// Registers should be returned (TRAP doesn't modify registers)
|
|
310
|
+
assert.strictEqual(result.ok.registers.get(0), tryAsU64(0xdeadbeefn));
|
|
311
|
+
assert.strictEqual(result.ok.registers.get(5), tryAsU64(0xcafebaben));
|
|
312
|
+
});
|
|
313
|
+
it("should return remaining gas after execution", async () => {
|
|
314
|
+
const ext = createExt();
|
|
315
|
+
const code = BytesBlob.blobFrom(MINIMAL_PROGRAM);
|
|
316
|
+
const initResult = await ext.machineInit(code, tryAsProgramCounter(0));
|
|
317
|
+
assert.strictEqual(initResult.isOk, true);
|
|
318
|
+
const machineId = initResult.ok;
|
|
319
|
+
const regs = emptyRegisters();
|
|
320
|
+
const result = await ext.machineInvoke(machineId, tryAsBigGas(1000n), regs);
|
|
321
|
+
assert.strictEqual(result.isOk, true);
|
|
322
|
+
// TRAP costs 1 gas, so remaining should be 999
|
|
323
|
+
const remaining = Number(result.ok.gas);
|
|
324
|
+
assert.ok(remaining < 1000);
|
|
325
|
+
assert.ok(remaining >= 0);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
163
328
|
});
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CoreIndex, Segment } from "#@typeberry/block";
|
|
2
2
|
import { type WorkPackageHash } from "#@typeberry/block/refine-context.js";
|
|
3
3
|
import type { WorkItemExtrinsic } from "#@typeberry/block/work-item.js";
|
|
4
4
|
import type { WorkPackage } from "#@typeberry/block/work-package.js";
|
|
5
5
|
import { WorkReport } from "#@typeberry/block/work-report.js";
|
|
6
|
-
import { WorkExecResult, WorkResult } from "#@typeberry/block/work-result.js";
|
|
7
|
-
import { type KnownSizeArray } from "#@typeberry/collections";
|
|
8
6
|
import type { ChainSpec, PvmBackend } from "#@typeberry/config";
|
|
9
7
|
import type { StatesDb } from "#@typeberry/database";
|
|
10
|
-
import {
|
|
11
|
-
import { type Blake2b, type WithHash } from "#@typeberry/hash";
|
|
8
|
+
import type { Blake2b, WithHash } from "#@typeberry/hash";
|
|
12
9
|
import { Result } from "#@typeberry/utils";
|
|
10
|
+
import { type ImportedSegment, type PerWorkItem } from "./refine.js";
|
|
11
|
+
export type { ImportedSegment, PerWorkItem, RefineItemResult } from "./refine.js";
|
|
13
12
|
export type RefineResult = {
|
|
14
13
|
report: WorkReport;
|
|
15
14
|
exports: PerWorkItem<Segment[]>;
|
|
16
15
|
};
|
|
17
|
-
export type RefineItemResult = {
|
|
18
|
-
result: WorkResult;
|
|
19
|
-
exports: readonly Segment[];
|
|
20
|
-
};
|
|
21
16
|
export declare enum RefineError {
|
|
22
17
|
/** State for context anchor block or lookup anchor is not found in the DB. */
|
|
23
18
|
StateMissing = 0,
|
|
@@ -28,16 +23,11 @@ export declare enum RefineError {
|
|
|
28
23
|
/** Authorization error. */
|
|
29
24
|
AuthorizationError = 3
|
|
30
25
|
}
|
|
31
|
-
export type PerWorkItem<T> = KnownSizeArray<T, "for each work item">;
|
|
32
|
-
export type ImportedSegment = {
|
|
33
|
-
index: SegmentIndex;
|
|
34
|
-
data: Segment;
|
|
35
|
-
};
|
|
36
26
|
export declare class InCore {
|
|
37
27
|
readonly chainSpec: ChainSpec;
|
|
38
28
|
private readonly states;
|
|
39
|
-
private readonly
|
|
40
|
-
private readonly
|
|
29
|
+
private readonly isAuthorized;
|
|
30
|
+
private readonly refineItem;
|
|
41
31
|
constructor(chainSpec: ChainSpec, states: StatesDb, pvmBackend: PvmBackend, blake2b: Blake2b);
|
|
42
32
|
/**
|
|
43
33
|
* Work-report computation function.
|
|
@@ -50,11 +40,6 @@ export declare class InCore {
|
|
|
50
40
|
* https://graypaper.fluffylabs.dev/#/ab2cdbd/1b7f021b7f02?v=0.7.2
|
|
51
41
|
*/
|
|
52
42
|
refine(workPackageAndHash: WithHash<WorkPackageHash, WorkPackage>, core: CoreIndex, imports: PerWorkItem<ImportedSegment[]>, extrinsics: PerWorkItem<WorkItemExtrinsic[]>): Promise<Result<RefineResult, RefineError>>;
|
|
53
|
-
private amalgamateWorkReport;
|
|
54
|
-
private authorizePackage;
|
|
55
|
-
private refineItem;
|
|
56
|
-
extractWorkResult(execResult: ReturnValue<ServiceGas>): WorkExecResult;
|
|
57
|
-
private getServiceCode;
|
|
58
|
-
private createRefineExternalities;
|
|
43
|
+
private static amalgamateWorkReport;
|
|
59
44
|
}
|
|
60
45
|
//# sourceMappingURL=in-core.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-core.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/in-core/in-core.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"in-core.d.ts","sourceRoot":"","sources":["../../../../../packages/jam/in-core/in-core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAsB,KAAK,eAAe,EAAmB,MAAM,oCAAoC,CAAC;AAC/G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAmB,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAG9E,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIzD,OAAO,EAAe,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAiC,MAAM,aAAa,CAAC;AAEpG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;CACjC,CAAC;AAEF,oBAAY,WAAW;IACrB,8EAA8E;IAC9E,YAAY,IAAI;IAChB,qFAAqF;IACrF,iBAAiB,IAAI;IACrB,wEAAwE;IACxE,uBAAuB,IAAI;IAC3B,2BAA2B;IAC3B,kBAAkB,IAAI;CACvB;AAID,qBAAa,MAAM;aAKC,SAAS,EAAE,SAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAGlB,SAAS,EAAE,SAAS,EACnB,MAAM,EAAE,QAAQ,EACjC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO;IAMlB;;;;;;;;;OASG;IACG,MAAM,CACV,kBAAkB,EAAE,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,EAC1D,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,WAAW,CAAC,eAAe,EAAE,CAAC,EACvC,UAAU,EAAE,WAAW,CAAC,iBAAiB,EAAE,CAAC,GAC3C,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IAwF7C,OAAO,CAAC,MAAM,CAAC,oBAAoB;CAsDpC"}
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { W_C } from "#@typeberry/block/gp-constants.js";
|
|
3
|
-
import { WorkPackageInfo, } from "#@typeberry/block/refine-context.js";
|
|
1
|
+
import { WorkPackageInfo } from "#@typeberry/block/refine-context.js";
|
|
4
2
|
import { WorkPackageSpec, WorkReport } from "#@typeberry/block/work-report.js";
|
|
5
|
-
import {
|
|
6
|
-
import { Bytes, BytesBlob } from "#@typeberry/bytes";
|
|
7
|
-
import { codec, Encoder } from "#@typeberry/codec";
|
|
3
|
+
import { Bytes } from "#@typeberry/bytes";
|
|
8
4
|
import { asKnownSize, FixedSizeArray } from "#@typeberry/collections";
|
|
9
|
-
import { PvmExecutor, ReturnStatus } from "#@typeberry/executor";
|
|
10
5
|
import { HASH_SIZE } from "#@typeberry/hash";
|
|
11
6
|
import { Logger } from "#@typeberry/logger";
|
|
12
7
|
import { tryAsU8, tryAsU16, tryAsU32 } from "#@typeberry/numbers";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
8
|
+
import { assertEmpty, Result } from "#@typeberry/utils";
|
|
9
|
+
import { AuthorizationError, IsAuthorized } from "./is-authorized.js";
|
|
10
|
+
import { Refine } from "./refine.js";
|
|
16
11
|
export var RefineError;
|
|
17
12
|
(function (RefineError) {
|
|
18
13
|
/** State for context anchor block or lookup anchor is not found in the DB. */
|
|
@@ -24,39 +19,17 @@ export var RefineError;
|
|
|
24
19
|
/** Authorization error. */
|
|
25
20
|
RefineError[RefineError["AuthorizationError"] = 3] = "AuthorizationError";
|
|
26
21
|
})(RefineError || (RefineError = {}));
|
|
27
|
-
var ServiceCodeError;
|
|
28
|
-
(function (ServiceCodeError) {
|
|
29
|
-
/** Service id is not found in the state. */
|
|
30
|
-
ServiceCodeError[ServiceCodeError["ServiceNotFound"] = 0] = "ServiceNotFound";
|
|
31
|
-
/** Expected service code does not match the state one. */
|
|
32
|
-
ServiceCodeError[ServiceCodeError["ServiceCodeMismatch"] = 1] = "ServiceCodeMismatch";
|
|
33
|
-
/** Code preimage missing. */
|
|
34
|
-
ServiceCodeError[ServiceCodeError["ServiceCodeMissing"] = 2] = "ServiceCodeMissing";
|
|
35
|
-
/** Code blob is too big. */
|
|
36
|
-
ServiceCodeError[ServiceCodeError["ServiceCodeTooBig"] = 3] = "ServiceCodeTooBig";
|
|
37
|
-
})(ServiceCodeError || (ServiceCodeError = {}));
|
|
38
|
-
var AuthorizationError;
|
|
39
|
-
(function (AuthorizationError) {
|
|
40
|
-
})(AuthorizationError || (AuthorizationError = {}));
|
|
41
22
|
const logger = Logger.new(import.meta.filename, "refine");
|
|
42
|
-
/** https://graypaper.fluffylabs.dev/#/ab2cdbd/2ffe002ffe00?v=0.7.2 */
|
|
43
|
-
const ARGS_CODEC = codec.object({
|
|
44
|
-
core: codec.varU32.convert((x) => tryAsU32(x), (x) => tryAsCoreIndex(x)),
|
|
45
|
-
workItemIndex: codec.varU32,
|
|
46
|
-
serviceId: codec.varU32.asOpaque(),
|
|
47
|
-
payloadLength: codec.varU32,
|
|
48
|
-
packageHash: codec.bytes(HASH_SIZE).asOpaque(),
|
|
49
|
-
});
|
|
50
23
|
export class InCore {
|
|
51
24
|
chainSpec;
|
|
52
25
|
states;
|
|
53
|
-
|
|
54
|
-
|
|
26
|
+
isAuthorized;
|
|
27
|
+
refineItem;
|
|
55
28
|
constructor(chainSpec, states, pvmBackend, blake2b) {
|
|
56
29
|
this.chainSpec = chainSpec;
|
|
57
30
|
this.states = states;
|
|
58
|
-
this.
|
|
59
|
-
this.
|
|
31
|
+
this.isAuthorized = new IsAuthorized(chainSpec, pvmBackend, blake2b);
|
|
32
|
+
this.refineItem = new Refine(chainSpec, pvmBackend, blake2b);
|
|
60
33
|
}
|
|
61
34
|
/**
|
|
62
35
|
* Work-report computation function.
|
|
@@ -70,13 +43,14 @@ export class InCore {
|
|
|
70
43
|
*/
|
|
71
44
|
async refine(workPackageAndHash, core, imports, extrinsics) {
|
|
72
45
|
const workPackageHash = workPackageAndHash.hash;
|
|
73
|
-
const { context,
|
|
46
|
+
const { context, authToken, authCodeHash, authCodeHost, authConfiguration, items, ...rest } = workPackageAndHash.data;
|
|
74
47
|
assertEmpty(rest);
|
|
75
48
|
// TODO [ToDr] Verify BEEFY root
|
|
76
49
|
// TODO [ToDr] Verify prerequisites
|
|
77
50
|
logger.log `[core:${core}] Attempting to refine work package with ${items.length} items.`;
|
|
78
|
-
// TODO [ToDr] GP link
|
|
79
51
|
// Verify anchor block
|
|
52
|
+
// https://graypaper.fluffylabs.dev/#/ab2cdbd/15cd0215cd02?v=0.7.2
|
|
53
|
+
// TODO [ToDr] Validation
|
|
80
54
|
const state = this.states.getState(context.anchor);
|
|
81
55
|
if (state === null) {
|
|
82
56
|
return Result.error(RefineError.StateMissing, () => `State at anchor block ${context.anchor} is missing.`);
|
|
@@ -96,7 +70,7 @@ export class InCore {
|
|
|
96
70
|
return Result.error(RefineError.InvalidLookupAnchorSlot, () => `Lookup anchor slot does not match the one is state. Ours: ${lookupState.timeslot}, expected: ${context.lookupAnchorSlot}`);
|
|
97
71
|
}
|
|
98
72
|
// Check authorization
|
|
99
|
-
const authResult = await this.
|
|
73
|
+
const authResult = await this.isAuthorized.invoke(state, core, authToken, authCodeHost, authCodeHash, authConfiguration);
|
|
100
74
|
if (authResult.isError) {
|
|
101
75
|
return Result.error(RefineError.AuthorizationError, () => `Authorization error: ${AuthorizationError[authResult.error]}: ${authResult.details()}.`);
|
|
102
76
|
}
|
|
@@ -106,14 +80,14 @@ export class InCore {
|
|
|
106
80
|
const refineResults = [];
|
|
107
81
|
for (const [idx, item] of items.entries()) {
|
|
108
82
|
logger.info `[core:${core}][i:${idx}] Refining item for service ${item.service}.`;
|
|
109
|
-
const result = await this.refineItem(state, lookupState, idx, item, imports, extrinsics, core, workPackageHash, exportOffset);
|
|
83
|
+
const result = await this.refineItem.invoke(state, lookupState, idx, item, imports, extrinsics, core, workPackageHash, exportOffset);
|
|
110
84
|
refineResults.push(result);
|
|
111
85
|
exportOffset += result.exports.length;
|
|
112
86
|
}
|
|
113
87
|
// amalgamate the work report now
|
|
114
|
-
return Result.ok(
|
|
88
|
+
return Result.ok(InCore.amalgamateWorkReport(asKnownSize(refineResults), authResult.ok, workPackageHash, context, core));
|
|
115
89
|
}
|
|
116
|
-
amalgamateWorkReport(refineResults, authResult, workPackageHash, context, coreIndex) {
|
|
90
|
+
static amalgamateWorkReport(refineResults, authResult, workPackageHash, context, coreIndex) {
|
|
117
91
|
// unzip exports and work results for each work item
|
|
118
92
|
const exports = refineResults.map((x) => x.exports);
|
|
119
93
|
const results = refineResults.map((x) => x.result);
|
|
@@ -156,148 +130,4 @@ export class InCore {
|
|
|
156
130
|
exports: asKnownSize(exports),
|
|
157
131
|
};
|
|
158
132
|
}
|
|
159
|
-
async authorizePackage(_authorization, _authCodeHost, _authCodeHash, _parametrization) {
|
|
160
|
-
// TODO [ToDr] Check authorization?
|
|
161
|
-
const authorizerHash = Bytes.zero(HASH_SIZE).asOpaque();
|
|
162
|
-
const authorizationGasUsed = tryAsServiceGas(0);
|
|
163
|
-
const authorizationOutput = BytesBlob.empty();
|
|
164
|
-
return Result.ok({
|
|
165
|
-
authorizerHash,
|
|
166
|
-
authorizationGasUsed,
|
|
167
|
-
authorizationOutput,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
async refineItem(state, lookupState, idx, item, allImports, allExtrinsics, coreIndex, workPackageHash, exportOffset) {
|
|
171
|
-
const payloadHash = this.blake2b.hashBytes(item.payload);
|
|
172
|
-
const baseResult = {
|
|
173
|
-
serviceId: item.service,
|
|
174
|
-
codeHash: item.codeHash,
|
|
175
|
-
payloadHash,
|
|
176
|
-
gas: item.refineGasLimit,
|
|
177
|
-
};
|
|
178
|
-
const imports = allImports[idx];
|
|
179
|
-
const extrinsics = allExtrinsics[idx];
|
|
180
|
-
const baseLoad = {
|
|
181
|
-
importedSegments: tryAsU32(imports.length),
|
|
182
|
-
extrinsicCount: tryAsU32(extrinsics.length),
|
|
183
|
-
extrinsicSize: tryAsU32(extrinsics.reduce((acc, x) => acc + x.length, 0)),
|
|
184
|
-
};
|
|
185
|
-
const maybeCode = this.getServiceCode(state, idx, item);
|
|
186
|
-
if (maybeCode.isError) {
|
|
187
|
-
const error = maybeCode.error === ServiceCodeError.ServiceCodeTooBig
|
|
188
|
-
? WorkExecResultKind.codeOversize
|
|
189
|
-
: WorkExecResultKind.badCode;
|
|
190
|
-
return {
|
|
191
|
-
exports: [],
|
|
192
|
-
result: WorkResult.create({
|
|
193
|
-
...baseResult,
|
|
194
|
-
result: WorkExecResult.error(error),
|
|
195
|
-
load: WorkRefineLoad.create({
|
|
196
|
-
...baseLoad,
|
|
197
|
-
gasUsed: tryAsServiceGas(item.refineGasLimit),
|
|
198
|
-
exportedSegments: tryAsU32(0),
|
|
199
|
-
}),
|
|
200
|
-
}),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
const code = maybeCode.ok;
|
|
204
|
-
const externalities = this.createRefineExternalities({
|
|
205
|
-
payload: item.payload,
|
|
206
|
-
imports: allImports,
|
|
207
|
-
extrinsics: allExtrinsics,
|
|
208
|
-
currentServiceId: item.service,
|
|
209
|
-
lookupState,
|
|
210
|
-
exportOffset,
|
|
211
|
-
});
|
|
212
|
-
const executor = await PvmExecutor.createRefineExecutor(item.service, code, externalities, this.pvmBackend);
|
|
213
|
-
const args = Encoder.encodeObject(ARGS_CODEC, {
|
|
214
|
-
serviceId: item.service,
|
|
215
|
-
core: coreIndex,
|
|
216
|
-
workItemIndex: tryAsU32(idx),
|
|
217
|
-
payloadLength: tryAsU32(item.payload.length),
|
|
218
|
-
packageHash: workPackageHash,
|
|
219
|
-
});
|
|
220
|
-
const execResult = await executor.run(args, item.refineGasLimit);
|
|
221
|
-
const exports = externalities.refine.getExportedSegments();
|
|
222
|
-
if (exports.length !== item.exportCount) {
|
|
223
|
-
return {
|
|
224
|
-
exports,
|
|
225
|
-
result: WorkResult.create({
|
|
226
|
-
...baseResult,
|
|
227
|
-
result: WorkExecResult.error(WorkExecResultKind.incorrectNumberOfExports),
|
|
228
|
-
load: WorkRefineLoad.create({
|
|
229
|
-
...baseLoad,
|
|
230
|
-
gasUsed: tryAsServiceGas(item.refineGasLimit),
|
|
231
|
-
exportedSegments: tryAsU32(0),
|
|
232
|
-
}),
|
|
233
|
-
}),
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
const result = this.extractWorkResult(execResult);
|
|
237
|
-
return {
|
|
238
|
-
exports,
|
|
239
|
-
result: WorkResult.create({
|
|
240
|
-
...baseResult,
|
|
241
|
-
result,
|
|
242
|
-
load: WorkRefineLoad.create({
|
|
243
|
-
...baseLoad,
|
|
244
|
-
gasUsed: tryAsServiceGas(execResult.consumedGas),
|
|
245
|
-
exportedSegments: tryAsU32(exports.length),
|
|
246
|
-
}),
|
|
247
|
-
}),
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
extractWorkResult(execResult) {
|
|
251
|
-
if (execResult.status === ReturnStatus.OK) {
|
|
252
|
-
const slice = execResult.memorySlice;
|
|
253
|
-
// TODO [ToDr] Verify the output size and change digestTooBig?
|
|
254
|
-
return WorkExecResult.ok(BytesBlob.blobFrom(slice));
|
|
255
|
-
}
|
|
256
|
-
switch (execResult.status) {
|
|
257
|
-
case ReturnStatus.OOG:
|
|
258
|
-
return WorkExecResult.error(WorkExecResultKind.outOfGas);
|
|
259
|
-
case ReturnStatus.PANIC:
|
|
260
|
-
return WorkExecResult.error(WorkExecResultKind.panic);
|
|
261
|
-
default:
|
|
262
|
-
assertNever(execResult);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
getServiceCode(state, idx, item) {
|
|
266
|
-
const serviceId = item.service;
|
|
267
|
-
const service = state.getService(serviceId);
|
|
268
|
-
// TODO [ToDr] GP link
|
|
269
|
-
// missing service
|
|
270
|
-
if (service === null) {
|
|
271
|
-
return Result.error(ServiceCodeError.ServiceNotFound, () => `[i:${idx}] Service ${serviceId} is missing in state.`);
|
|
272
|
-
}
|
|
273
|
-
// TODO [ToDr] GP link
|
|
274
|
-
// TODO [ToDr] shall we rather use the old codehash instead
|
|
275
|
-
if (!service.getInfo().codeHash.isEqualTo(item.codeHash)) {
|
|
276
|
-
return Result.error(ServiceCodeError.ServiceCodeMismatch, () => `[i:${idx}] Service ${serviceId} has invalid code hash. Ours: ${service.getInfo().codeHash}, expected: ${item.codeHash}`);
|
|
277
|
-
}
|
|
278
|
-
const code = service.getPreimage(item.codeHash.asOpaque());
|
|
279
|
-
if (code === null) {
|
|
280
|
-
return Result.error(ServiceCodeError.ServiceCodeMissing, () => `[i:${idx}] Code ${item.codeHash} for service ${serviceId} was not found.`);
|
|
281
|
-
}
|
|
282
|
-
if (code.length > W_C) {
|
|
283
|
-
return Result.error(ServiceCodeError.ServiceCodeTooBig, () => `[i:${idx}] Code ${item.codeHash} for service ${serviceId} is too big! ${code.length} bytes vs ${W_C} bytes max.`);
|
|
284
|
-
}
|
|
285
|
-
return Result.ok(code);
|
|
286
|
-
}
|
|
287
|
-
createRefineExternalities(args) {
|
|
288
|
-
// TODO [ToDr] Pass all required fetch data
|
|
289
|
-
const fetchExternalities = FetchExternalities.createForRefine({
|
|
290
|
-
entropy: undefined,
|
|
291
|
-
...args,
|
|
292
|
-
}, this.chainSpec);
|
|
293
|
-
const refine = RefineExternalitiesImpl.create({
|
|
294
|
-
currentServiceId: args.currentServiceId,
|
|
295
|
-
lookupState: args.lookupState,
|
|
296
|
-
exportOffset: args.exportOffset,
|
|
297
|
-
});
|
|
298
|
-
return {
|
|
299
|
-
fetchExternalities,
|
|
300
|
-
refine,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
133
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
2
4
|
import { before, describe, it } from "node:test";
|
|
3
5
|
import { tryAsCoreIndex, tryAsServiceGas, tryAsServiceId, tryAsTimeSlot } from "#@typeberry/block";
|
|
4
6
|
import { RefineContext } from "#@typeberry/block/refine-context.js";
|
|
@@ -6,21 +8,46 @@ import { WorkItem } from "#@typeberry/block/work-item.js";
|
|
|
6
8
|
import { tryAsWorkItemsCount, WorkPackage } from "#@typeberry/block/work-package.js";
|
|
7
9
|
import { Bytes, BytesBlob } from "#@typeberry/bytes";
|
|
8
10
|
import { Encoder } from "#@typeberry/codec";
|
|
9
|
-
import { asKnownSize, FixedSizeArray } from "#@typeberry/collections";
|
|
11
|
+
import { asKnownSize, FixedSizeArray, HashDictionary } from "#@typeberry/collections";
|
|
10
12
|
import { PvmBackend, tinyChainSpec } from "#@typeberry/config";
|
|
11
13
|
import { InMemoryStates } from "#@typeberry/database";
|
|
12
14
|
import { Blake2b, HASH_SIZE, WithHash } from "#@typeberry/hash";
|
|
13
|
-
import { tryAsU16 } from "#@typeberry/numbers";
|
|
14
|
-
import {
|
|
15
|
+
import { tryAsU16, tryAsU32, tryAsU64 } from "#@typeberry/numbers";
|
|
16
|
+
import { InMemoryService, InMemoryState, PreimageItem, ServiceAccountInfo } from "#@typeberry/state";
|
|
15
17
|
import { InCore, RefineError } from "./in-core.js";
|
|
18
|
+
// Load the authorizer PVM fixture (checks authToken === authConfiguration).
|
|
19
|
+
const AUTHORIZER_PVM = BytesBlob.blobFrom(readFileSync(resolve(import.meta.dirname, "fixtures/authorizer.pvm")));
|
|
20
|
+
const AUTH_SERVICE_ID = tryAsServiceId(1);
|
|
16
21
|
let blake2b;
|
|
17
22
|
before(async () => {
|
|
18
23
|
blake2b = await Blake2b.createHasher();
|
|
19
24
|
});
|
|
20
|
-
function
|
|
25
|
+
function getAuthCodeHash() {
|
|
26
|
+
return blake2b.hashBytes(AUTHORIZER_PVM).asOpaque();
|
|
27
|
+
}
|
|
28
|
+
function createService(serviceId, codeHash, code) {
|
|
29
|
+
return new InMemoryService(serviceId, {
|
|
30
|
+
info: ServiceAccountInfo.create({
|
|
31
|
+
codeHash: codeHash.asOpaque(),
|
|
32
|
+
balance: tryAsU64(10_000_000_000),
|
|
33
|
+
accumulateMinGas: tryAsServiceGas(0n),
|
|
34
|
+
onTransferMinGas: tryAsServiceGas(0n),
|
|
35
|
+
storageUtilisationBytes: tryAsU64(0),
|
|
36
|
+
storageUtilisationCount: tryAsU32(0),
|
|
37
|
+
gratisStorage: tryAsU64(0),
|
|
38
|
+
created: tryAsTimeSlot(0),
|
|
39
|
+
lastAccumulation: tryAsTimeSlot(0),
|
|
40
|
+
parentService: tryAsServiceId(0),
|
|
41
|
+
}),
|
|
42
|
+
preimages: HashDictionary.fromEntries([PreimageItem.create({ hash: codeHash.asOpaque(), blob: code })].map((x) => [x.hash, x])),
|
|
43
|
+
lookupHistory: HashDictionary.fromEntries([]),
|
|
44
|
+
storage: new Map(),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function createWorkItem(codeHash, serviceId = 1) {
|
|
21
48
|
return WorkItem.create({
|
|
22
49
|
service: tryAsServiceId(serviceId),
|
|
23
|
-
codeHash
|
|
50
|
+
codeHash,
|
|
24
51
|
payload: BytesBlob.empty(),
|
|
25
52
|
refineGasLimit: tryAsServiceGas(1_000_000),
|
|
26
53
|
accumulateGasLimit: tryAsServiceGas(1_000_000),
|
|
@@ -29,12 +56,12 @@ function createWorkItem(serviceId = 1) {
|
|
|
29
56
|
exportCount: tryAsU16(0),
|
|
30
57
|
});
|
|
31
58
|
}
|
|
32
|
-
function createWorkPackage(anchorHash, stateRoot, lookupAnchorSlot = 0) {
|
|
59
|
+
function createWorkPackage(anchorHash, stateRoot, authCodeHash, lookupAnchorSlot = 0) {
|
|
33
60
|
return WorkPackage.create({
|
|
34
|
-
|
|
35
|
-
authCodeHost:
|
|
36
|
-
authCodeHash
|
|
37
|
-
|
|
61
|
+
authToken: BytesBlob.empty(),
|
|
62
|
+
authCodeHost: AUTH_SERVICE_ID,
|
|
63
|
+
authCodeHash,
|
|
64
|
+
authConfiguration: BytesBlob.empty(),
|
|
38
65
|
context: RefineContext.create({
|
|
39
66
|
anchor: anchorHash,
|
|
40
67
|
stateRoot,
|
|
@@ -43,7 +70,7 @@ function createWorkPackage(anchorHash, stateRoot, lookupAnchorSlot = 0) {
|
|
|
43
70
|
lookupAnchorSlot: tryAsTimeSlot(lookupAnchorSlot),
|
|
44
71
|
prerequisites: [],
|
|
45
72
|
}),
|
|
46
|
-
items: FixedSizeArray.new([createWorkItem()], tryAsWorkItemsCount(1)),
|
|
73
|
+
items: FixedSizeArray.new([createWorkItem(authCodeHash)], tryAsWorkItemsCount(1)),
|
|
47
74
|
});
|
|
48
75
|
}
|
|
49
76
|
function hashWorkPackage(spec, workPackage) {
|
|
@@ -59,7 +86,8 @@ describe("InCore", () => {
|
|
|
59
86
|
const inCore = new InCore(spec, states, PvmBackend.BuiltIn, blake2b);
|
|
60
87
|
const anchorHash = Bytes.fill(HASH_SIZE, 1).asOpaque();
|
|
61
88
|
const stateRoot = Bytes.zero(HASH_SIZE).asOpaque();
|
|
62
|
-
const
|
|
89
|
+
const authCodeHash = getAuthCodeHash();
|
|
90
|
+
const workPackage = createWorkPackage(anchorHash, stateRoot, authCodeHash);
|
|
63
91
|
const result = await inCore.refine(hashWorkPackage(spec, workPackage), tryAsCoreIndex(0), asKnownSize([[]]), asKnownSize([[]]));
|
|
64
92
|
assert.strictEqual(result.isError, true);
|
|
65
93
|
assert.strictEqual(result.error, RefineError.StateMissing);
|
|
@@ -68,13 +96,17 @@ describe("InCore", () => {
|
|
|
68
96
|
const spec = tinyChainSpec;
|
|
69
97
|
const states = new InMemoryStates(spec);
|
|
70
98
|
const inCore = new InCore(spec, states, PvmBackend.BuiltIn, blake2b);
|
|
99
|
+
const authCodeHash = getAuthCodeHash();
|
|
71
100
|
const anchorHash = Bytes.fill(HASH_SIZE, 1).asOpaque();
|
|
72
|
-
const state =
|
|
101
|
+
const state = InMemoryState.partial(spec, {
|
|
102
|
+
timeslot: tryAsTimeSlot(16),
|
|
103
|
+
services: new Map([[AUTH_SERVICE_ID, createService(AUTH_SERVICE_ID, authCodeHash, AUTHORIZER_PVM)]]),
|
|
104
|
+
});
|
|
73
105
|
await states.insertInitialState(anchorHash, state);
|
|
74
106
|
const correctStateRoot = await states.getStateRoot(state);
|
|
75
|
-
const workPackage = createWorkPackage(anchorHash, correctStateRoot, state.timeslot);
|
|
107
|
+
const workPackage = createWorkPackage(anchorHash, correctStateRoot, authCodeHash, state.timeslot);
|
|
76
108
|
const result = await inCore.refine(hashWorkPackage(spec, workPackage), tryAsCoreIndex(0), asKnownSize([[]]), asKnownSize([[]]));
|
|
77
|
-
assert.strictEqual(result.isOk, true);
|
|
109
|
+
assert.strictEqual(result.isOk, true, `Expected OK but got error: ${result.isError ? result.details() : ""}`);
|
|
78
110
|
assert.strictEqual(result.ok.report.coreIndex, 0);
|
|
79
111
|
assert.strictEqual(result.ok.report.results.length, 1);
|
|
80
112
|
});
|