@typeberry/lib 0.5.10-ca4935b → 0.5.10-ec38e0b

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.
Files changed (50) hide show
  1. package/package.json +1 -1
  2. package/packages/jam/block/work-package.d.ts +7 -7
  3. package/packages/jam/block/work-package.d.ts.map +1 -1
  4. package/packages/jam/block/work-package.js +12 -12
  5. package/packages/jam/executor/pvm-executor.d.ts +7 -0
  6. package/packages/jam/executor/pvm-executor.d.ts.map +1 -1
  7. package/packages/jam/executor/pvm-executor.js +15 -0
  8. package/packages/jam/in-core/externalities/refine.d.ts +2 -2
  9. package/packages/jam/in-core/externalities/refine.d.ts.map +1 -1
  10. package/packages/jam/in-core/externalities/refine.js +10 -3
  11. package/packages/jam/in-core/externalities/refine.test.js +53 -0
  12. package/packages/jam/in-core/in-core.d.ts +7 -22
  13. package/packages/jam/in-core/in-core.d.ts.map +1 -1
  14. package/packages/jam/in-core/in-core.js +16 -184
  15. package/packages/jam/in-core/in-core.test.js +47 -15
  16. package/packages/jam/in-core/is-authorized.d.ts +33 -0
  17. package/packages/jam/in-core/is-authorized.d.ts.map +1 -0
  18. package/packages/jam/in-core/is-authorized.js +72 -0
  19. package/packages/jam/in-core/is-authorized.test.d.ts +2 -0
  20. package/packages/jam/in-core/is-authorized.test.d.ts.map +1 -0
  21. package/packages/jam/in-core/is-authorized.test.js +125 -0
  22. package/packages/jam/in-core/refine.d.ts +34 -0
  23. package/packages/jam/in-core/refine.d.ts.map +1 -0
  24. package/packages/jam/in-core/refine.js +176 -0
  25. package/packages/jam/in-core/refine.test.d.ts +2 -0
  26. package/packages/jam/in-core/refine.test.d.ts.map +1 -0
  27. package/packages/jam/in-core/refine.test.js +6 -0
  28. package/packages/jam/jam-host-calls/accumulate/bless.js +9 -9
  29. package/packages/jam/jam-host-calls/externalities/partial-state.d.ts +1 -1
  30. package/packages/jam/jam-host-calls/externalities/refine-externalities.d.ts +1 -1
  31. package/packages/jam/jam-host-calls/externalities/refine-externalities.d.ts.map +1 -1
  32. package/packages/jam/jam-host-calls/general/fetch.d.ts +40 -40
  33. package/packages/jam/jam-host-calls/general/fetch.d.ts.map +1 -1
  34. package/packages/jam/jam-host-calls/general/fetch.js +30 -30
  35. package/packages/jam/jam-host-calls/general/fetch.test.js +17 -14
  36. package/packages/jam/jamnp-s/protocol/ce-133-work-package-submission.d.ts +2 -2
  37. package/packages/jam/transition/accumulate/accumulation-result-merge-utils.js +48 -39
  38. package/packages/jam/transition/externalities/accumulate-externalities.d.ts +2 -2
  39. package/packages/jam/transition/externalities/accumulate-externalities.d.ts.map +1 -1
  40. package/packages/jam/transition/externalities/accumulate-externalities.js +20 -7
  41. package/packages/jam/transition/externalities/accumulate-externalities.test.js +74 -4
  42. package/packages/jam/transition/externalities/index.d.ts +1 -0
  43. package/packages/jam/transition/externalities/index.d.ts.map +1 -1
  44. package/packages/jam/transition/externalities/index.js +1 -0
  45. package/packages/jam/transition/externalities/is-authorized-fetch-externalities.d.ts +22 -0
  46. package/packages/jam/transition/externalities/is-authorized-fetch-externalities.d.ts.map +1 -0
  47. package/packages/jam/transition/externalities/is-authorized-fetch-externalities.js +41 -0
  48. package/packages/jam/transition/externalities/refine-fetch-externalities.d.ts +7 -7
  49. package/packages/jam/transition/externalities/refine-fetch-externalities.d.ts.map +1 -1
  50. package/packages/jam/transition/externalities/refine-fetch-externalities.js +17 -9
@@ -14,7 +14,7 @@ import { HostCallResult } from "./results.js";
14
14
  * Ω_Y signature: Ω_Y(ρ, φ, μ, p, n, r, i, ī, x̄, 𝐢, ...)
15
15
  *
16
16
  * Context parameter mapping
17
- * Is-Authorized: Ω_Y(ρ, φ, μ, 𝐩, ∅, ∅, ∅, ∅, ∅, ∅, ∅)
17
+ * IsAuthorized: Ω_Y(ρ, φ, μ, 𝐩, ∅, ∅, ∅, ∅, ∅, ∅, ∅)
18
18
  * https://graypaper.fluffylabs.dev/#/ab2cdbd/2e43012e4301?v=0.7.2
19
19
  * Refine: Ω_Y(ρ, φ, μ, p, H₀, r, i, ī, x̄, ∅, (m,e))
20
20
  * https://graypaper.fluffylabs.dev/#/ab2cdbd/2fe0012fe001?v=0.7.2
@@ -22,13 +22,13 @@ import { HostCallResult } from "./results.js";
22
22
  * https://graypaper.fluffylabs.dev/#/ab2cdbd/30c00030c000?v=0.7.2
23
23
  *
24
24
  * Kind availability per context:
25
- * Kind 0 (constants) all contexts
26
- * Kind 1 (n) Refine (H₀), Accumulate (η'₀)
27
- * Kind 2 (r) Refine only
28
- * Kind 3-4 (x̄ extrinsics) Refine only
29
- * Kind 5-6 (ī imports) Refine only
30
- * Kind 7-13 (p work pkg) Is-Authorized, Refine
31
- * Kind 14-15 (𝐢 acc items) Accumulate only
25
+ * Kind 0 (constants) - all contexts
26
+ * Kind 1 (n) - Refine (H₀), Accumulate (η'₀)
27
+ * Kind 2 (r) - Refine only
28
+ * Kind 3-4 (x̄ extrinsics) - Refine only
29
+ * Kind 5-6 (ī imports) - Refine only
30
+ * Kind 7-13 (p work pkg) - IsAuthorized, Refine
31
+ * Kind 14-15 (𝐢 acc items) - Accumulate only
32
32
  */
33
33
  export var FetchContext;
34
34
  (function (FetchContext) {
@@ -76,25 +76,25 @@ export class Fetch {
76
76
  }
77
77
  getValue(kind, regs) {
78
78
  const ext = this.fetch;
79
- // Kind 0: constants all contexts
79
+ // Kind 0: constants - all contexts
80
80
  if (kind === FetchKind.Constants) {
81
81
  return ext.constants();
82
82
  }
83
- // Kind 1: entropy Refine, Accumulate
83
+ // Kind 1: entropy - Refine, Accumulate
84
84
  if (kind === FetchKind.Entropy) {
85
85
  if (ext.context === FetchContext.IsAuthorized) {
86
86
  return null;
87
87
  }
88
88
  return ext.entropy();
89
89
  }
90
- // Kind 2: authorizer trace Refine only
90
+ // Kind 2: authorizer trace - Refine only
91
91
  if (kind === FetchKind.AuthorizerTrace) {
92
92
  if (ext.context !== FetchContext.Refine) {
93
93
  return null;
94
94
  }
95
95
  return ext.authorizerTrace();
96
96
  }
97
- // Kind 3: other work item extrinsics Refine only
97
+ // Kind 3: other work item extrinsics - Refine only
98
98
  if (kind === FetchKind.OtherWorkItemExtrinsics) {
99
99
  if (ext.context !== FetchContext.Refine) {
100
100
  return null;
@@ -103,7 +103,7 @@ export class Fetch {
103
103
  const index = regs.get(12);
104
104
  return ext.workItemExtrinsic(workItem, index);
105
105
  }
106
- // Kind 4: my extrinsics Refine only
106
+ // Kind 4: my extrinsics - Refine only
107
107
  if (kind === FetchKind.MyExtrinsics) {
108
108
  if (ext.context !== FetchContext.Refine) {
109
109
  return null;
@@ -111,7 +111,7 @@ export class Fetch {
111
111
  const index = regs.get(11);
112
112
  return ext.workItemExtrinsic(null, index);
113
113
  }
114
- // Kind 5: other work item imports Refine only
114
+ // Kind 5: other work item imports - Refine only
115
115
  if (kind === FetchKind.OtherWorkItemImports) {
116
116
  if (ext.context !== FetchContext.Refine) {
117
117
  return null;
@@ -120,7 +120,7 @@ export class Fetch {
120
120
  const index = regs.get(12);
121
121
  return ext.workItemImport(workItem, index);
122
122
  }
123
- // Kind 6: my imports Refine only
123
+ // Kind 6: my imports - Refine only
124
124
  if (kind === FetchKind.MyImports) {
125
125
  if (ext.context !== FetchContext.Refine) {
126
126
  return null;
@@ -128,42 +128,42 @@ export class Fetch {
128
128
  const index = regs.get(11);
129
129
  return ext.workItemImport(null, index);
130
130
  }
131
- // Kind 7: work package Is-Authorized, Refine
131
+ // Kind 7: work package - IsAuthorized, Refine
132
132
  if (kind === FetchKind.WorkPackage) {
133
133
  if (ext.context === FetchContext.Accumulate) {
134
134
  return null;
135
135
  }
136
136
  return ext.workPackage();
137
137
  }
138
- // Kind 8: authorizer Is-Authorized, Refine
139
- if (kind === FetchKind.Authorizer) {
138
+ // Kind 8: auth configuration - IsAuthorized, Refine
139
+ if (kind === FetchKind.AuthConfiguration) {
140
140
  if (ext.context === FetchContext.Accumulate) {
141
141
  return null;
142
142
  }
143
- return ext.authorizer();
143
+ return ext.authConfiguration();
144
144
  }
145
- // Kind 9: authorization token Is-Authorized, Refine
146
- if (kind === FetchKind.AuthorizationToken) {
145
+ // Kind 9: authorization token - IsAuthorized, Refine
146
+ if (kind === FetchKind.AuthToken) {
147
147
  if (ext.context === FetchContext.Accumulate) {
148
148
  return null;
149
149
  }
150
- return ext.authorizationToken();
150
+ return ext.authToken();
151
151
  }
152
- // Kind 10: refine context Is-Authorized, Refine
152
+ // Kind 10: refine context - IsAuthorized, Refine
153
153
  if (kind === FetchKind.RefineContext) {
154
154
  if (ext.context === FetchContext.Accumulate) {
155
155
  return null;
156
156
  }
157
157
  return ext.refineContext();
158
158
  }
159
- // Kind 11: all work items Is-Authorized, Refine
159
+ // Kind 11: all work items - IsAuthorized, Refine
160
160
  if (kind === FetchKind.AllWorkItems) {
161
161
  if (ext.context === FetchContext.Accumulate) {
162
162
  return null;
163
163
  }
164
164
  return ext.allWorkItems();
165
165
  }
166
- // Kind 12: one work item Is-Authorized, Refine
166
+ // Kind 12: one work item - IsAuthorized, Refine
167
167
  if (kind === FetchKind.OneWorkItem) {
168
168
  if (ext.context === FetchContext.Accumulate) {
169
169
  return null;
@@ -171,7 +171,7 @@ export class Fetch {
171
171
  const workItem = regs.get(11);
172
172
  return ext.oneWorkItem(workItem);
173
173
  }
174
- // Kind 13: work item payload Is-Authorized, Refine
174
+ // Kind 13: work item payload - IsAuthorized, Refine
175
175
  if (kind === FetchKind.WorkItemPayload) {
176
176
  if (ext.context === FetchContext.Accumulate) {
177
177
  return null;
@@ -179,14 +179,14 @@ export class Fetch {
179
179
  const workItem = regs.get(11);
180
180
  return ext.workItemPayload(workItem);
181
181
  }
182
- // Kind 14: all transfers and operands Accumulate only
182
+ // Kind 14: all transfers and operands - Accumulate only
183
183
  if (kind === FetchKind.AllTransfersAndOperands) {
184
184
  if (ext.context !== FetchContext.Accumulate) {
185
185
  return null;
186
186
  }
187
187
  return ext.allTransfersAndOperands();
188
188
  }
189
- // Kind 15: one transfer or operand Accumulate only
189
+ // Kind 15: one transfer or operand - Accumulate only
190
190
  if (kind === FetchKind.OneTransferOrOperand) {
191
191
  if (ext.context !== FetchContext.Accumulate) {
192
192
  return null;
@@ -207,8 +207,8 @@ export var FetchKind;
207
207
  FetchKind[FetchKind["OtherWorkItemImports"] = 5] = "OtherWorkItemImports";
208
208
  FetchKind[FetchKind["MyImports"] = 6] = "MyImports";
209
209
  FetchKind[FetchKind["WorkPackage"] = 7] = "WorkPackage";
210
- FetchKind[FetchKind["Authorizer"] = 8] = "Authorizer";
211
- FetchKind[FetchKind["AuthorizationToken"] = 9] = "AuthorizationToken";
210
+ FetchKind[FetchKind["AuthConfiguration"] = 8] = "AuthConfiguration";
211
+ FetchKind[FetchKind["AuthToken"] = 9] = "AuthToken";
212
212
  FetchKind[FetchKind["RefineContext"] = 10] = "RefineContext";
213
213
  FetchKind[FetchKind["AllWorkItems"] = 11] = "AllWorkItems";
214
214
  FetchKind[FetchKind["OneWorkItem"] = 12] = "OneWorkItem";
@@ -35,9 +35,12 @@ describe("Fetch", () => {
35
35
  it("should write empty result and set IN_OUT_REG to NONE if fetch returns null", async () => {
36
36
  const currentServiceId = tryAsServiceId(10_000);
37
37
  const fetchMock = new RefineFetchMock();
38
- // authorizerTraceResponse is null by default Kind 2 legitimately returns null
38
+ // oneWorkItem returns null when the work item index has no mock response registered
39
39
  const blob = BytesBlob.blobFromNumbers([]);
40
- const { registers, memory, readBack } = prepareRegsAndMemory(blob, FetchKind.AuthorizerTrace);
40
+ const { registers, memory, readBack } = prepareRegsAndMemory(blob, FetchKind.OneWorkItem);
41
+ // set work item index to one that has no response → oneWorkItem returns null
42
+ registers.set(11, tryAsU64(999));
43
+ fetchMock.oneWorkItemResponses.set("999", null);
41
44
  const fetch = new Fetch(currentServiceId, fetchMock);
42
45
  const result = await fetch.execute(gas, registers, memory);
43
46
  assert.strictEqual(result, undefined);
@@ -203,7 +206,7 @@ describe("Fetch", () => {
203
206
  const blob = BytesBlob.blobFromNumbers([201, 202, 203]);
204
207
  const fetchMock = new RefineFetchMock();
205
208
  fetchMock.authorizerResponse = blob;
206
- const { registers, memory, readBack, expectedLength } = prepareRegsAndMemory(blob, FetchKind.Authorizer);
209
+ const { registers, memory, readBack, expectedLength } = prepareRegsAndMemory(blob, FetchKind.AuthConfiguration);
207
210
  const fetch = new Fetch(currentServiceId, fetchMock);
208
211
  const result = await fetch.execute(gas, registers, memory);
209
212
  assert.strictEqual(result, undefined);
@@ -215,7 +218,7 @@ describe("Fetch", () => {
215
218
  const blob = BytesBlob.blobFromNumbers([210, 211, 212]);
216
219
  const fetchMock = new RefineFetchMock();
217
220
  fetchMock.authorizationTokenResponse = blob;
218
- const { registers, memory, readBack, expectedLength } = prepareRegsAndMemory(blob, FetchKind.AuthorizationToken);
221
+ const { registers, memory, readBack, expectedLength } = prepareRegsAndMemory(blob, FetchKind.AuthToken);
219
222
  const fetch = new Fetch(currentServiceId, fetchMock);
220
223
  const result = await fetch.execute(gas, registers, memory);
221
224
  assert.strictEqual(result, undefined);
@@ -314,8 +317,8 @@ describe("Fetch", () => {
314
317
  FetchKind.OtherWorkItemImports,
315
318
  FetchKind.MyImports,
316
319
  FetchKind.WorkPackage,
317
- FetchKind.Authorizer,
318
- FetchKind.AuthorizationToken,
320
+ FetchKind.AuthConfiguration,
321
+ FetchKind.AuthToken,
319
322
  FetchKind.RefineContext,
320
323
  FetchKind.AllWorkItems,
321
324
  FetchKind.OneWorkItem,
@@ -373,14 +376,14 @@ class RefineFetchMock {
373
376
  workItemPayloadData = [];
374
377
  constantsResponse = null;
375
378
  entropyResponse = null;
376
- authorizerTraceResponse = null;
379
+ authorizerTraceResponse = BytesBlob.empty();
377
380
  workItemExtrinsicResponses = new Map();
378
381
  workItemImportResponses = new Map();
379
- workPackageResponse = null;
380
- authorizerResponse = null;
381
- authorizationTokenResponse = null;
382
- refineContextResponse = null;
383
- allWorkItemsResponse = null;
382
+ workPackageResponse = BytesBlob.empty();
383
+ authorizerResponse = BytesBlob.empty();
384
+ authorizationTokenResponse = BytesBlob.empty();
385
+ refineContextResponse = BytesBlob.empty();
386
+ allWorkItemsResponse = BytesBlob.empty();
384
387
  oneWorkItemResponses = new Map();
385
388
  workItemPayloadResponses = new Map();
386
389
  constants() {
@@ -417,10 +420,10 @@ class RefineFetchMock {
417
420
  workPackage() {
418
421
  return this.workPackageResponse;
419
422
  }
420
- authorizer() {
423
+ authConfiguration() {
421
424
  return this.authorizerResponse;
422
425
  }
423
- authorizationToken() {
426
+ authToken() {
424
427
  return this.authorizationTokenResponse;
425
428
  }
426
429
  refineContext() {
@@ -29,8 +29,8 @@ export declare class CoreWorkPackage extends WithDebug {
29
29
  lookupAnchorSlot: import("@typeberry/codec").Descriptor<number & import("@typeberry/numbers").WithBytesRepresentation<4> & import("@typeberry/utils").WithOpaque<"TimeSlot[u32]">, import("@typeberry/bytes").Bytes<4>>;
30
30
  prerequisites: import("@typeberry/codec").Descriptor<(import("@typeberry/bytes").Bytes<32> & import("@typeberry/utils").WithOpaque<"WorkPackageHash">)[], import("@typeberry/codec").SequenceView<import("@typeberry/bytes").Bytes<32> & import("@typeberry/utils").WithOpaque<"WorkPackageHash">, import("@typeberry/bytes").Bytes<32>>>;
31
31
  }>>;
32
- authorization: import("@typeberry/codec").Descriptor<BytesBlob, BytesBlob>;
33
- parametrization: import("@typeberry/codec").Descriptor<BytesBlob, BytesBlob>;
32
+ authToken: import("@typeberry/codec").Descriptor<BytesBlob, BytesBlob>;
33
+ authConfiguration: import("@typeberry/codec").Descriptor<BytesBlob, BytesBlob>;
34
34
  items: import("@typeberry/codec").Descriptor<import("@typeberry/collections").FixedSizeArray<import("@typeberry/block").WorkItem, import("@typeberry/numbers").U8>, import("@typeberry/codec").SequenceView<import("@typeberry/block").WorkItem, import("@typeberry/codec").ViewOf<import("@typeberry/block").WorkItem, {
35
35
  service: import("@typeberry/codec").Descriptor<number & import("@typeberry/numbers").WithBytesRepresentation<4> & import("@typeberry/utils").WithOpaque<"ServiceId[u32]">, import("@typeberry/bytes").Bytes<4>>;
36
36
  codeHash: import("@typeberry/codec").Descriptor<import("@typeberry/bytes").Bytes<32> & import("@typeberry/utils").WithOpaque<"CodeHash">, import("@typeberry/bytes").Bytes<32>>;
@@ -44,47 +44,56 @@ function mergePrivilegedServices(mergeContext, [serviceId, { stateUpdate }]) {
44
44
  const currentDelegator = currentPrivilegedServices.delegator;
45
45
  const currentAssigners = currentPrivilegedServices.assigners;
46
46
  const { privilegedServices } = stateUpdate;
47
- if (privilegedServices !== null) {
48
- if (outputState.privilegedServices === null) {
49
- outputState.privilegedServices = PrivilegedServices.create({
50
- ...currentPrivilegedServices,
51
- });
52
- }
53
- if (serviceId === currentManager) {
54
- outputState.privilegedServices = PrivilegedServices.create({
55
- ...privilegedServices,
56
- });
57
- }
58
- if (serviceId === currentRegistrar) {
59
- const newRegistrar = updatePrivilegedService(currentPrivilegedServices.registrar, privilegedServicesUpdatedByManager.registrar, privilegedServices.registrar);
60
- outputState.privilegedServices = PrivilegedServices.create({
61
- ...outputState.privilegedServices,
62
- registrar: newRegistrar,
63
- });
64
- }
65
- if (serviceId === currentDelegator) {
66
- const newDelegator = updatePrivilegedService(currentPrivilegedServices.delegator, privilegedServicesUpdatedByManager.delegator, privilegedServices.delegator);
67
- outputState.privilegedServices = PrivilegedServices.create({
68
- ...outputState.privilegedServices,
69
- delegator: newDelegator,
70
- });
71
- }
72
- let shouldUpdateAssigners = false;
73
- const newAssigners = currentAssigners.map((currentAssigner, coreIndex) => {
74
- if (serviceId === currentAssigner) {
75
- const newAssigner = updatePrivilegedService(currentPrivilegedServices.assigners[coreIndex], privilegedServicesUpdatedByManager.assigners[coreIndex], privilegedServices.assigners[coreIndex]);
76
- shouldUpdateAssigners = shouldUpdateAssigners || newAssigner !== currentAssigner;
77
- return newAssigner;
78
- }
79
- return currentAssigner;
47
+ if (privilegedServices === null) {
48
+ return;
49
+ }
50
+ // initial value (ignore the update, because it might not be authorized)
51
+ if (outputState.privilegedServices === null) {
52
+ outputState.privilegedServices = PrivilegedServices.create({
53
+ ...currentPrivilegedServices,
54
+ });
55
+ }
56
+ // manager can override everything and it always takes precedence over
57
+ // everything else
58
+ if (serviceId === currentManager) {
59
+ outputState.privilegedServices = PrivilegedServices.create({
60
+ ...privilegedServices,
61
+ });
62
+ }
63
+ // current registrar can transfer out it's permissions, but only if
64
+ // it wasn't overwritten by manager in current run
65
+ if (serviceId === currentRegistrar) {
66
+ const newRegistrar = updatePrivilegedService(currentPrivilegedServices.registrar, privilegedServicesUpdatedByManager.registrar, privilegedServices.registrar);
67
+ outputState.privilegedServices = PrivilegedServices.create({
68
+ ...outputState.privilegedServices,
69
+ registrar: newRegistrar,
80
70
  });
81
- if (shouldUpdateAssigners) {
82
- const newAssignersPerCore = tryAsPerCore(newAssigners, chainSpec);
83
- outputState.privilegedServices = PrivilegedServices.create({
84
- ...outputState.privilegedServices,
85
- assigners: newAssignersPerCore,
86
- });
71
+ }
72
+ // current delegator can transfer out it's permissions, but only if
73
+ // it wasn't overwritten by manager in current run
74
+ if (serviceId === currentDelegator) {
75
+ const newDelegator = updatePrivilegedService(currentPrivilegedServices.delegator, privilegedServicesUpdatedByManager.delegator, privilegedServices.delegator);
76
+ outputState.privilegedServices = PrivilegedServices.create({
77
+ ...outputState.privilegedServices,
78
+ delegator: newDelegator,
79
+ });
80
+ }
81
+ let shouldUpdateAssigners = false;
82
+ // same with assigners - they are free to transfer out their core
83
+ const newAssigners = currentAssigners.map((currentAssigner, coreIndex) => {
84
+ if (serviceId === currentAssigner) {
85
+ const newAssigner = updatePrivilegedService(currentPrivilegedServices.assigners[coreIndex], privilegedServicesUpdatedByManager.assigners[coreIndex], privilegedServices.assigners[coreIndex]);
86
+ shouldUpdateAssigners = shouldUpdateAssigners || newAssigner !== currentAssigner;
87
+ return newAssigner;
87
88
  }
89
+ return currentAssigner;
90
+ });
91
+ if (shouldUpdateAssigners) {
92
+ const newAssignersPerCore = tryAsPerCore(newAssigners, chainSpec);
93
+ outputState.privilegedServices = PrivilegedServices.create({
94
+ ...outputState.privilegedServices,
95
+ assigners: newAssignersPerCore,
96
+ });
88
97
  }
89
98
  }
90
99
  function mergeValidatorsData(mergeContext, [serviceId, { stateUpdate }]) {
@@ -2,7 +2,7 @@ import { type CodeHash, type CoreIndex, type PerValidator, type ServiceGas, type
2
2
  import type { PreimageHash } from "#@typeberry/block/preimage.js";
3
3
  import type { AuthorizerHash } from "#@typeberry/block/refine-context.js";
4
4
  import { Bytes, type BytesBlob } from "#@typeberry/bytes";
5
- import type { FixedSizeArray } from "#@typeberry/collections";
5
+ import { type FixedSizeArray } from "#@typeberry/collections";
6
6
  import type { ChainSpec } from "#@typeberry/config";
7
7
  import { type Blake2b, type OpaqueHash } from "#@typeberry/hash";
8
8
  import { AccumulationStateUpdate, EjectError, ForgetPreimageError, type general, NewServiceError, type PartiallyUpdatedState, type PartialState, type PreimageStatus, ProvidePreimageError, RequestPreimageError, type TRANSFER_MEMO_BYTES, TransferError, UnprivilegedError, UpdatePrivilegesError } from "#@typeberry/jam-host-calls";
@@ -64,7 +64,7 @@ export declare class AccumulateExternalities implements PartialState, general.Ac
64
64
  upgradeService(codeHash: CodeHash, gas: U64, allowance: U64): void;
65
65
  updateValidatorsData(validatorsData: PerValidator<ValidatorData>): Result<OK, UnprivilegedError>;
66
66
  checkpoint(): void;
67
- updateAuthorizationQueue(coreIndex: CoreIndex, authQueue: FixedSizeArray<AuthorizerHash, AUTHORIZATION_QUEUE_SIZE>, assigners: ServiceId | null): Result<OK, UpdatePrivilegesError>;
67
+ updateAuthorizationQueue(coreIndex: CoreIndex, authQueue: FixedSizeArray<AuthorizerHash, AUTHORIZATION_QUEUE_SIZE>, newAssigner: ServiceId | null): Result<OK, UpdatePrivilegesError>;
68
68
  updatePrivilegedServices(manager: ServiceId | null, assigners: PerCore<ServiceId>, delegator: ServiceId | null, registrar: ServiceId | null, autoAccumulateServices: Map<ServiceId, ServiceGas>): Result<OK, UpdatePrivilegesError>;
69
69
  yield(hash: OpaqueHash): void;
70
70
  providePreimage(serviceId: ServiceId | null, preimage: BytesBlob): Result<OK, ProvidePreimageError>;
@@ -1 +1 @@
1
- {"version":3,"file":"accumulate-externalities.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/externalities/accumulate-externalities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accumulate-externalities.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/externalities/accumulate-externalities.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { tryAsServiceGas, tryAsServiceId, tryAsTimeSlot, } from "#@typeberry/block";
2
2
  import { MIN_PUBLIC_SERVICE_INDEX } from "#@typeberry/block/gp-constants.js";
3
3
  import { Bytes } from "#@typeberry/bytes";
4
+ import { asKnownSize } from "#@typeberry/collections";
4
5
  import { HASH_SIZE } from "#@typeberry/hash";
5
6
  import { AccumulationStateUpdate, clampU64ToU32, EjectError, ForgetPreimageError, NewServiceError, PendingTransfer, PreimageStatusKind, ProvidePreimageError, RequestPreimageError, slotsToPreimageStatus, TransferError, UnprivilegedError, UpdatePrivilegesError, writeServiceIdAsLeBytes, } from "#@typeberry/jam-host-calls";
6
7
  import { Logger } from "#@typeberry/logger";
@@ -354,19 +355,31 @@ export class AccumulateExternalities {
354
355
  /** https://graypaper.fluffylabs.dev/#/9a08063/362202362202?v=0.6.6 */
355
356
  this.checkpointedState = AccumulationStateUpdate.copyFrom(this.updatedState.stateUpdate);
356
357
  }
357
- updateAuthorizationQueue(coreIndex, authQueue, assigners) {
358
+ updateAuthorizationQueue(coreIndex, authQueue, newAssigner) {
358
359
  /** https://graypaper.fluffylabs.dev/#/7e6ff6a/36a40136a401?v=0.6.7 */
359
360
  // NOTE `coreIndex` is already verified in the HC, so this is infallible.
360
- const currentAssigners = this.updatedState.getPrivilegedServices().assigners[coreIndex];
361
- if (currentAssigners !== this.currentServiceId) {
362
- logger.trace `Current service id (${this.currentServiceId}) is not an auth manager of core ${coreIndex} (expected: ${currentAssigners}) and cannot update authorization queue.`;
363
- return Result.error(UpdatePrivilegesError.UnprivilegedService, () => `Service ${this.currentServiceId} not assigner for core ${coreIndex} (expected: ${currentAssigners})`);
364
- }
365
- if (assigners === null) {
361
+ const privilegedServices = this.updatedState.getPrivilegedServices();
362
+ const currentAssigners = privilegedServices.assigners;
363
+ const assigner = currentAssigners[coreIndex];
364
+ if (assigner !== this.currentServiceId) {
365
+ logger.trace `Current service id (${this.currentServiceId}) is not an auth manager of core ${coreIndex} (expected: ${assigner}) and cannot update authorization queue.`;
366
+ return Result.error(UpdatePrivilegesError.UnprivilegedService, () => `Service ${this.currentServiceId} not assigner for core ${coreIndex} (expected: ${assigner})`);
367
+ }
368
+ if (newAssigner === null) {
366
369
  logger.trace `The new auth manager is not a valid service id.`;
367
370
  return Result.error(UpdatePrivilegesError.InvalidServiceId, () => `New auth manager is null for core ${coreIndex}`);
368
371
  }
372
+ // update the authorization queue
369
373
  this.updatedState.stateUpdate.authorizationQueues.set(coreIndex, authQueue);
374
+ // move permissions to the new assigner
375
+ const assigners = currentAssigners.slice();
376
+ assigners[coreIndex] = newAssigner;
377
+ this.updatedState.stateUpdate.privilegedServices = PrivilegedServices.create({
378
+ ...privilegedServices,
379
+ // since coreindex is validated, we do not alter the size,
380
+ // hence it's safe to convert back
381
+ assigners: asKnownSize(assigners),
382
+ });
370
383
  return Result.ok(OK);
371
384
  }
372
385
  updatePrivilegedServices(manager, assigners, delegator, registrar, autoAccumulateServices) {
@@ -6,7 +6,7 @@ import { asKnownSize, FixedSizeArray, HashDictionary } from "#@typeberry/collect
6
6
  import { tinyChainSpec } from "#@typeberry/config";
7
7
  import { BANDERSNATCH_KEY_BYTES, BLS_KEY_BYTES, ED25519_KEY_BYTES } from "#@typeberry/crypto";
8
8
  import { Blake2b, HASH_SIZE } from "#@typeberry/hash";
9
- import { EjectError, ForgetPreimageError, NewServiceError, PartiallyUpdatedState, PendingTransfer, PreimageStatusKind, ProvidePreimageError, RequestPreimageError, TRANSFER_MEMO_BYTES, TransferError, UnprivilegedError, UpdatePrivilegesError, writeServiceIdAsLeBytes, } from "#@typeberry/jam-host-calls";
9
+ import { CURRENT_SERVICE_ID, EjectError, ForgetPreimageError, NewServiceError, PartiallyUpdatedState, PendingTransfer, PreimageStatusKind, ProvidePreimageError, RequestPreimageError, TRANSFER_MEMO_BYTES, TransferError, UnprivilegedError, UpdatePrivilegesError, writeServiceIdAsLeBytes, } from "#@typeberry/jam-host-calls";
10
10
  import { tryAsU32, tryAsU64 } from "#@typeberry/numbers";
11
11
  import { AUTHORIZATION_QUEUE_SIZE, InMemoryService, InMemoryState, LookupHistoryItem, PreimageItem, PrivilegedServices, ServiceAccountInfo, StorageItem, tryAsLookupHistorySlots, tryAsPerCore, UpdatePreimage, UpdateService, VALIDATOR_META_BYTES, ValidatorData, } from "#@typeberry/state";
12
12
  import { testState } from "#@typeberry/state/test.utils.js";
@@ -663,16 +663,28 @@ describe("PartialState.upgradeService", () => {
663
663
  });
664
664
  });
665
665
  describe("PartialState.updateAuthorizationQueue", () => {
666
- it("should update the authorization queue for a given core index", () => {
666
+ it("should update the authorization queue and transfer the assigner for the given core", () => {
667
667
  const state = partiallyUpdatedState();
668
+ const initialPrivileged = state.state.privilegedServices;
668
669
  const partialState = new AccumulateExternalities(tinyChainSpec, blake2b, state, tryAsServiceId(0), tryAsServiceId(10), tryAsTimeSlot(16));
669
670
  const coreIndex = tryAsCoreIndex(0);
670
- const assigners = tryAsServiceId(0);
671
+ const newAssigner = tryAsServiceId(99);
671
672
  const queue = FixedSizeArray.new(Array.from({ length: AUTHORIZATION_QUEUE_SIZE }, () => Bytes.fill(HASH_SIZE, 0xee).asOpaque()), AUTHORIZATION_QUEUE_SIZE);
672
673
  // when
673
- partialState.updateAuthorizationQueue(coreIndex, queue, assigners);
674
+ const result = partialState.updateAuthorizationQueue(coreIndex, queue, newAssigner);
674
675
  // then
676
+ deepEqual(result, Result.ok(OK));
675
677
  assert.deepStrictEqual(state.stateUpdate.authorizationQueues.get(coreIndex), queue);
678
+ // the privilegedServices update must be written, with only the targeted
679
+ // core's assigner transferred; all other fields must be preserved.
680
+ const updated = state.stateUpdate.privilegedServices;
681
+ assert.ok(updated !== null, "stateUpdate.privilegedServices should be written");
682
+ assert.strictEqual(updated.assigners[0], newAssigner);
683
+ assert.strictEqual(updated.assigners[1], initialPrivileged.assigners[1]);
684
+ assert.strictEqual(updated.manager, initialPrivileged.manager);
685
+ assert.strictEqual(updated.delegator, initialPrivileged.delegator);
686
+ assert.strictEqual(updated.registrar, initialPrivileged.registrar);
687
+ assert.strictEqual(updated.autoAccumulateServices, initialPrivileged.autoAccumulateServices);
676
688
  });
677
689
  it("should return InvalidServiceId when given auth manager is invalid", () => {
678
690
  const state = partiallyUpdatedState();
@@ -685,6 +697,8 @@ describe("PartialState.updateAuthorizationQueue", () => {
685
697
  // then
686
698
  deepEqual(result, Result.error(UpdatePrivilegesError.InvalidServiceId, () => "New auth manager is null for core 0"));
687
699
  assert.deepStrictEqual(state.stateUpdate.authorizationQueues.get(coreIndex), undefined);
700
+ // no partial privilegedServices write on error
701
+ assert.strictEqual(state.stateUpdate.privilegedServices, null);
688
702
  });
689
703
  it("should return UnprivilegedService when current service is not privileged", () => {
690
704
  const state = partiallyUpdatedState();
@@ -701,6 +715,8 @@ describe("PartialState.updateAuthorizationQueue", () => {
701
715
  // then
702
716
  deepEqual(result, Result.error(UpdatePrivilegesError.UnprivilegedService, () => "Service 0 not assigner for core 0 (expected: 1)"));
703
717
  assert.deepStrictEqual(state.stateUpdate.authorizationQueues.get(coreIndex), undefined);
718
+ // no partial privilegedServices write on error
719
+ assert.strictEqual(state.stateUpdate.privilegedServices, null);
704
720
  });
705
721
  it("should return UnprivilegedService before InvalidServiceId if given auth manager is incorrect, but current servis is also unprivileged", () => {
706
722
  const state = partiallyUpdatedState();
@@ -717,6 +733,60 @@ describe("PartialState.updateAuthorizationQueue", () => {
717
733
  // then
718
734
  deepEqual(result, Result.error(UpdatePrivilegesError.UnprivilegedService, () => "Service 0 not assigner for core 0 (expected: 1)"));
719
735
  assert.deepStrictEqual(state.stateUpdate.authorizationQueues.get(coreIndex), undefined);
736
+ // no partial privilegedServices write on error
737
+ assert.strictEqual(state.stateUpdate.privilegedServices, null);
738
+ });
739
+ it("should succeed on a self-transfer using CURRENT_SERVICE_ID", () => {
740
+ const state = partiallyUpdatedState();
741
+ // inject a service info for CURRENT_SERVICE_ID so it can act as the
742
+ // current (and assigning) service on core 0
743
+ const baseService = state.state.services.get(tryAsServiceId(0));
744
+ if (baseService === undefined) {
745
+ throw new Error("Invalid service!");
746
+ }
747
+ state.state.services.set(CURRENT_SERVICE_ID, new InMemoryService(CURRENT_SERVICE_ID, {
748
+ info: baseService.data.info,
749
+ preimages: HashDictionary.new(),
750
+ lookupHistory: HashDictionary.new(),
751
+ storage: new Map(),
752
+ }));
753
+ state.state.privilegedServices = PrivilegedServices.create({
754
+ ...state.state.privilegedServices,
755
+ assigners: asOpaqueType(FixedSizeArray.new([CURRENT_SERVICE_ID, tryAsServiceId(0)], tinyChainSpec.coresCount)),
756
+ });
757
+ const partialState = new AccumulateExternalities(tinyChainSpec, blake2b, state, CURRENT_SERVICE_ID, tryAsServiceId(10), tryAsTimeSlot(16));
758
+ const coreIndex = tryAsCoreIndex(0);
759
+ const queue = FixedSizeArray.new(Array.from({ length: AUTHORIZATION_QUEUE_SIZE }, () => Bytes.fill(HASH_SIZE, 0xee).asOpaque()), AUTHORIZATION_QUEUE_SIZE);
760
+ // when
761
+ const result = partialState.updateAuthorizationQueue(coreIndex, queue, CURRENT_SERVICE_ID);
762
+ // then
763
+ deepEqual(result, Result.ok(OK));
764
+ assert.deepStrictEqual(state.stateUpdate.authorizationQueues.get(coreIndex), queue);
765
+ const updated = state.stateUpdate.privilegedServices;
766
+ assert.ok(updated !== null, "stateUpdate.privilegedServices should be written");
767
+ assert.strictEqual(updated.assigners[0], CURRENT_SERVICE_ID);
768
+ assert.strictEqual(updated.assigners[1], tryAsServiceId(0));
769
+ });
770
+ it("should prevent the previous assigner from re-assigning after transfer", () => {
771
+ const state = partiallyUpdatedState();
772
+ const partialState = new AccumulateExternalities(tinyChainSpec, blake2b, state, tryAsServiceId(0), tryAsServiceId(10), tryAsTimeSlot(16));
773
+ const coreIndex = tryAsCoreIndex(0);
774
+ const newAssigner = tryAsServiceId(99);
775
+ const firstQueue = FixedSizeArray.new(Array.from({ length: AUTHORIZATION_QUEUE_SIZE }, () => Bytes.fill(HASH_SIZE, 0xee).asOpaque()), AUTHORIZATION_QUEUE_SIZE);
776
+ const secondQueue = FixedSizeArray.new(Array.from({ length: AUTHORIZATION_QUEUE_SIZE }, () => Bytes.fill(HASH_SIZE, 0xff).asOpaque()), AUTHORIZATION_QUEUE_SIZE);
777
+ // when: first call succeeds and transfers the assigner to service 99
778
+ const first = partialState.updateAuthorizationQueue(coreIndex, firstQueue, newAssigner);
779
+ // and the previous assigner (service 0) immediately tries to re-assign
780
+ const second = partialState.updateAuthorizationQueue(coreIndex, secondQueue, tryAsServiceId(0));
781
+ // then
782
+ deepEqual(first, Result.ok(OK));
783
+ deepEqual(second, Result.error(UpdatePrivilegesError.UnprivilegedService, () => "Service 0 not assigner for core 0 (expected: 99)"));
784
+ // the first queue remains — the failing second call must not overwrite it
785
+ assert.deepStrictEqual(state.stateUpdate.authorizationQueues.get(coreIndex), firstQueue);
786
+ // and the transferred assigner is still in place
787
+ const updated = state.stateUpdate.privilegedServices;
788
+ assert.ok(updated !== null);
789
+ assert.strictEqual(updated.assigners[0], newAssigner);
720
790
  });
721
791
  });
722
792
  describe("PartialState.updatePrivilegedServices", () => {
@@ -1,5 +1,6 @@
1
1
  export * from "./accumulate-externalities.js";
2
2
  export * from "./accumulate-fetch-externalities.js";
3
3
  export * from "./fetch-externalities.js";
4
+ export * from "./is-authorized-fetch-externalities.js";
4
5
  export * from "./refine-fetch-externalities.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/externalities/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/externalities/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,wCAAwC,CAAC;AACvD,cAAc,iCAAiC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from "./accumulate-externalities.js";
2
2
  export * from "./accumulate-fetch-externalities.js";
3
3
  export * from "./fetch-externalities.js";
4
+ export * from "./is-authorized-fetch-externalities.js";
4
5
  export * from "./refine-fetch-externalities.js";
@@ -0,0 +1,22 @@
1
+ import { BytesBlob } from "#@typeberry/bytes";
2
+ import type { ChainSpec } from "#@typeberry/config";
3
+ import { general } from "#@typeberry/jam-host-calls";
4
+ import type { U64 } from "#@typeberry/numbers";
5
+ export declare class IsAuthorizedFetchExternalities implements general.IIsAuthorizedFetch {
6
+ private readonly chainSpec;
7
+ private readonly params;
8
+ readonly context = general.FetchContext.IsAuthorized;
9
+ constructor(chainSpec: ChainSpec, params: {
10
+ authToken: BytesBlob;
11
+ authConfiguration: BytesBlob;
12
+ });
13
+ constants(): BytesBlob;
14
+ workPackage(): BytesBlob;
15
+ authConfiguration(): BytesBlob;
16
+ authToken(): BytesBlob;
17
+ refineContext(): BytesBlob;
18
+ allWorkItems(): BytesBlob;
19
+ oneWorkItem(_workItem: U64): BytesBlob | null;
20
+ workItemPayload(_workItem: U64): BytesBlob | null;
21
+ }
22
+ //# sourceMappingURL=is-authorized-fetch-externalities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-authorized-fetch-externalities.d.ts","sourceRoot":"","sources":["../../../../../../packages/jam/transition/externalities/is-authorized-fetch-externalities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAG9C,qBAAa,8BAA+B,YAAW,OAAO,CAAC,kBAAkB;IAI7E,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,QAAQ,CAAC,OAAO,qCAAqC;gBAGlC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE;QACvB,SAAS,EAAE,SAAS,CAAC;QACrB,iBAAiB,EAAE,SAAS,CAAC;KAC9B;IAGH,SAAS,IAAI,SAAS;IAKtB,WAAW,IAAI,SAAS;IAIxB,iBAAiB,IAAI,SAAS;IAI9B,SAAS,IAAI,SAAS;IAKtB,aAAa,IAAI,SAAS;IAK1B,YAAY,IAAI,SAAS;IAKzB,WAAW,CAAC,SAAS,EAAE,GAAG,GAAG,SAAS,GAAG,IAAI;IAK7C,eAAe,CAAC,SAAS,EAAE,GAAG,GAAG,SAAS,GAAG,IAAI;CAGlD"}