@acala-network/chopsticks-core 1.5.0 → 1.5.2

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.
@@ -0,0 +1,6 @@
1
+ import type { HexString } from '@polkadot/util/types';
2
+ import type { Block } from '../block.js';
3
+ import type { InherentProvider } from './index.js';
4
+ export declare class ProcessPendingRenewals implements InherentProvider {
5
+ createInherents(newBlock: Block): Promise<HexString[]>;
6
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "ProcessPendingRenewals", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return ProcessPendingRenewals;
9
+ }
10
+ });
11
+ const _types = require("@polkadot/types");
12
+ class ProcessPendingRenewals {
13
+ async createInherents(newBlock) {
14
+ const parent = await newBlock.parentBlock;
15
+ if (!parent) throw new Error('parent block not found');
16
+ const meta = await parent.meta;
17
+ if (!meta.tx.dataRenewal?.processPendingRenewals) {
18
+ return [];
19
+ }
20
+ // Bulletin's pallet-bulletin-data-renewal mandatory drain inherent.
21
+ // The pallet's on_finalize asserts PendingAutoRenewals was drained, so
22
+ // the inherent must be included in every block, matching the pallet's
23
+ // unconditional create_inherent.
24
+ const inherent = new _types.GenericExtrinsic(meta.registry, meta.tx.dataRenewal.processPendingRenewals());
25
+ return [
26
+ inherent.toHex()
27
+ ];
28
+ }
29
+ }
@@ -1,6 +1,7 @@
1
1
  import type { HexString } from '@polkadot/util/types';
2
2
  import type { Block } from '../block.js';
3
3
  import type { BuildBlockParams } from '../txpool.js';
4
+ import { ProcessPendingRenewals } from './data-renewal.js';
4
5
  import { ParaInherentEnter } from './para-enter.js';
5
6
  import { SetBabeRandomness } from './parachain/babe-randomness.js';
6
7
  import { SetNimbusAuthorInherent } from './parachain/nimbus-author-inherent.js';
@@ -10,4 +11,4 @@ import { SetTransactionStorageProof } from './transaction-storage.js';
10
11
  export interface InherentProvider {
11
12
  createInherents(newBlock: Block, params: BuildBlockParams): Promise<HexString[]>;
12
13
  }
13
- export declare const inherentProviders: (ParaInherentEnter | SetBabeRandomness | SetNimbusAuthorInherent | SetValidationData | SetTimestamp | SetTransactionStorageProof)[];
14
+ export declare const inherentProviders: (ProcessPendingRenewals | ParaInherentEnter | SetBabeRandomness | SetNimbusAuthorInherent | SetValidationData | SetTimestamp | SetTransactionStorageProof)[];
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "inherentProviders", {
8
8
  return inherentProviders;
9
9
  }
10
10
  });
11
+ const _datarenewal = require("./data-renewal.js");
11
12
  const _paraenter = require("./para-enter.js");
12
13
  const _baberandomness = require("./parachain/babe-randomness.js");
13
14
  const _nimbusauthorinherent = require("./parachain/nimbus-author-inherent.js");
@@ -20,5 +21,6 @@ const inherentProviders = [
20
21
  new _paraenter.ParaInherentEnter(),
21
22
  new _nimbusauthorinherent.SetNimbusAuthorInherent(),
22
23
  new _baberandomness.SetBabeRandomness(),
23
- new _transactionstorage.SetTransactionStorageProof()
24
+ new _transactionstorage.SetTransactionStorageProof(),
25
+ new _datarenewal.ProcessPendingRenewals()
24
26
  ];
@@ -172,9 +172,22 @@ class RemoteStorageLayer {
172
172
  }, 'RemoteStorageLayer getKeysPaged');
173
173
  const isChild = (0, _index.isPrefixedChildKey)(prefix);
174
174
  const minPrefixLen = isChild ? _index.CHILD_PREFIX_LENGTH : _index.PREFIX_LENGTH;
175
- // KeyCache groups by the first `minPrefixLen` chars; it cannot correctly answer queries
176
- // whose prefix is longer than that grouping width, so proxy directly to upstream.
177
- if (prefix.length < minPrefixLen || startKey.length < minPrefixLen || prefix.length > minPrefixLen || startKey.length > minPrefixLen) {
175
+ // KeyCache groups by the first `minPrefixLen` chars; it cannot correctly answer queries whose PREFIX is
176
+ // off that grouping width, so those are proxied directly to upstream (a longer prefix would otherwise match
177
+ // on the truncated head and return keys that do not start with the requested prefix — smoldot's
178
+ // `clear_prefix` asserts `key.starts_with(prefix)`).
179
+ //
180
+ // `startKey` is a different matter: every CONTINUATION of a scan carries a full-length storage key by
181
+ // construction, and serving those from the cache is precisely what the cache is for. Bailing out on a long
182
+ // `startKey` makes each continuation page an upstream round-trip.
183
+ //
184
+ // But a long `startKey` is only cache-safe when it belongs to the SAME group as `prefix`. `KeyCache.next()`
185
+ // derives its range from the first `minPrefixLen` chars of the `startKey` alone and never checks the result
186
+ // against `prefix`, so a `startKey` from a different `minPrefixLen`-char group would be answered from that
187
+ // other group's range — returning a key that does not start with `prefix`. `!startKey.startsWith(prefix)`
188
+ // proxies those cross-group requests to upstream; genuine continuations (`startKey.startsWith(prefix)` by
189
+ // construction) still hit the cache. (Reported by @xlc on #1055.)
190
+ if (prefix.length !== minPrefixLen || startKey.length < minPrefixLen || !startKey.startsWith(prefix)) {
178
191
  return _class_private_field_get(this, _api).getKeysPaged(prefix, pageSize, startKey, _class_private_field_get(this, _at));
179
192
  }
180
193
  const startKeyEqualsPrefix = startKey === prefix;
@@ -281,7 +294,7 @@ class RemoteStorageLayer {
281
294
  _class_private_field_set(this, _db, db);
282
295
  }
283
296
  }
284
- var _store = /*#__PURE__*/ new WeakMap(), _keys = /*#__PURE__*/ new WeakMap(), _deletedPrefix = /*#__PURE__*/ new WeakMap(), _parent = /*#__PURE__*/ new WeakMap(), _addKey = /*#__PURE__*/ new WeakSet(), _removeKey = /*#__PURE__*/ new WeakSet();
297
+ var _store = /*#__PURE__*/ new WeakMap(), _keys = /*#__PURE__*/ new WeakMap(), _deletedPrefix = /*#__PURE__*/ new WeakMap(), _parent = /*#__PURE__*/ new WeakMap(), _addKey = /*#__PURE__*/ new WeakSet(), _removeKey = /*#__PURE__*/ new WeakSet(), _cacheParentValue = /*#__PURE__*/ new WeakSet();
285
298
  class StorageLayer {
286
299
  deleted(key) {
287
300
  if (_class_private_field_get(this, _store).has(key)) {
@@ -303,9 +316,9 @@ class StorageLayer {
303
316
  return "Deleted";
304
317
  }
305
318
  if (_class_private_field_get(this, _parent)) {
306
- const val = _class_private_field_get(this, _parent).get(key, false);
319
+ const val = await _class_private_field_get(this, _parent).get(key, false);
307
320
  if (cache) {
308
- _class_private_field_get(this, _store).set(key, val);
321
+ _class_private_method_get(this, _cacheParentValue, cacheParentValue).call(this, key, val);
309
322
  }
310
323
  return val;
311
324
  }
@@ -314,9 +327,9 @@ class StorageLayer {
314
327
  async getMany(keys, cache) {
315
328
  const result = [];
316
329
  const pending = [];
317
- const preloadedPromises = keys.map(async (key, idx)=>{
330
+ keys.forEach((key, idx)=>{
318
331
  if (_class_private_field_get(this, _store).has(key)) {
319
- result[idx] = await _class_private_field_get(this, _store).get(key);
332
+ result[idx] = _class_private_field_get(this, _store).get(key);
320
333
  } else if (_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
321
334
  result[idx] = "Deleted";
322
335
  } else {
@@ -330,12 +343,11 @@ class StorageLayer {
330
343
  const vals = await _class_private_field_get(this, _parent).getMany(pending.map((p)=>p.key), false);
331
344
  vals.forEach((val, idx)=>{
332
345
  if (cache) {
333
- _class_private_field_get(this, _store).set(pending[idx].key, val);
346
+ _class_private_method_get(this, _cacheParentValue, cacheParentValue).call(this, pending[idx].key, val);
334
347
  }
335
348
  result[pending[idx].idx] = val;
336
349
  });
337
350
  }
338
- await Promise.all(preloadedPromises);
339
351
  return result;
340
352
  }
341
353
  set(key, value) {
@@ -346,7 +358,7 @@ class StorageLayer {
346
358
  break;
347
359
  case "DeletedPrefix":
348
360
  _class_private_field_get(this, _deletedPrefix).push(key);
349
- for (const k of _class_private_field_get(this, _keys)){
361
+ for (const k of _class_private_field_get(this, _store).keys()){
350
362
  if (k.startsWith(key)) {
351
363
  _class_private_field_get(this, _store).set(k, "Deleted");
352
364
  _class_private_method_get(this, _removeKey, removeKey).call(this, k);
@@ -409,8 +421,7 @@ class StorageLayer {
409
421
  /**
410
422
  * Merge the storage layer into the given object, can be used to get sotrage diff.
411
423
  */ async mergeInto(into) {
412
- for (const [key, maybeValue] of _class_private_field_get(this, _store)){
413
- const value = await maybeValue;
424
+ for (const [key, value] of _class_private_field_get(this, _store)){
414
425
  if (value === "Deleted") {
415
426
  into[key] = null;
416
427
  } else {
@@ -421,6 +432,7 @@ class StorageLayer {
421
432
  constructor(parent){
422
433
  _class_private_method_init(this, _addKey);
423
434
  _class_private_method_init(this, _removeKey);
435
+ _class_private_method_init(this, _cacheParentValue);
424
436
  _class_private_field_init(this, _store, {
425
437
  writable: true,
426
438
  value: new Map()
@@ -455,3 +467,8 @@ function removeKey(key) {
455
467
  _class_private_field_get(this, _keys).splice(idx, 1);
456
468
  }
457
469
  }
470
+ function cacheParentValue(key, value) {
471
+ if (!_class_private_field_get(this, _store).has(key) && !_class_private_field_get(this, _deletedPrefix).some((dp)=>key.startsWith(dp))) {
472
+ _class_private_field_get(this, _store).set(key, value);
473
+ }
474
+ }
@@ -0,0 +1,6 @@
1
+ import type { HexString } from '@polkadot/util/types';
2
+ import type { Block } from '../block.js';
3
+ import type { InherentProvider } from './index.js';
4
+ export declare class ProcessPendingRenewals implements InherentProvider {
5
+ createInherents(newBlock: Block): Promise<HexString[]>;
6
+ }
@@ -0,0 +1,19 @@
1
+ import { GenericExtrinsic } from '@polkadot/types';
2
+ export class ProcessPendingRenewals {
3
+ async createInherents(newBlock) {
4
+ const parent = await newBlock.parentBlock;
5
+ if (!parent) throw new Error('parent block not found');
6
+ const meta = await parent.meta;
7
+ if (!meta.tx.dataRenewal?.processPendingRenewals) {
8
+ return [];
9
+ }
10
+ // Bulletin's pallet-bulletin-data-renewal mandatory drain inherent.
11
+ // The pallet's on_finalize asserts PendingAutoRenewals was drained, so
12
+ // the inherent must be included in every block, matching the pallet's
13
+ // unconditional create_inherent.
14
+ const inherent = new GenericExtrinsic(meta.registry, meta.tx.dataRenewal.processPendingRenewals());
15
+ return [
16
+ inherent.toHex()
17
+ ];
18
+ }
19
+ }
@@ -1,6 +1,7 @@
1
1
  import type { HexString } from '@polkadot/util/types';
2
2
  import type { Block } from '../block.js';
3
3
  import type { BuildBlockParams } from '../txpool.js';
4
+ import { ProcessPendingRenewals } from './data-renewal.js';
4
5
  import { ParaInherentEnter } from './para-enter.js';
5
6
  import { SetBabeRandomness } from './parachain/babe-randomness.js';
6
7
  import { SetNimbusAuthorInherent } from './parachain/nimbus-author-inherent.js';
@@ -10,4 +11,4 @@ import { SetTransactionStorageProof } from './transaction-storage.js';
10
11
  export interface InherentProvider {
11
12
  createInherents(newBlock: Block, params: BuildBlockParams): Promise<HexString[]>;
12
13
  }
13
- export declare const inherentProviders: (ParaInherentEnter | SetBabeRandomness | SetNimbusAuthorInherent | SetValidationData | SetTimestamp | SetTransactionStorageProof)[];
14
+ export declare const inherentProviders: (ProcessPendingRenewals | ParaInherentEnter | SetBabeRandomness | SetNimbusAuthorInherent | SetValidationData | SetTimestamp | SetTransactionStorageProof)[];
@@ -1,3 +1,4 @@
1
+ import { ProcessPendingRenewals } from './data-renewal.js';
1
2
  import { ParaInherentEnter } from './para-enter.js';
2
3
  import { SetBabeRandomness } from './parachain/babe-randomness.js';
3
4
  import { SetNimbusAuthorInherent } from './parachain/nimbus-author-inherent.js';
@@ -10,5 +11,6 @@ export const inherentProviders = [
10
11
  new ParaInherentEnter(),
11
12
  new SetNimbusAuthorInherent(),
12
13
  new SetBabeRandomness(),
13
- new SetTransactionStorageProof()
14
+ new SetTransactionStorageProof(),
15
+ new ProcessPendingRenewals()
14
16
  ];
@@ -106,9 +106,22 @@ export class RemoteStorageLayer {
106
106
  }, 'RemoteStorageLayer getKeysPaged');
107
107
  const isChild = isPrefixedChildKey(prefix);
108
108
  const minPrefixLen = isChild ? CHILD_PREFIX_LENGTH : PREFIX_LENGTH;
109
- // KeyCache groups by the first `minPrefixLen` chars; it cannot correctly answer queries
110
- // whose prefix is longer than that grouping width, so proxy directly to upstream.
111
- if (prefix.length < minPrefixLen || startKey.length < minPrefixLen || prefix.length > minPrefixLen || startKey.length > minPrefixLen) {
109
+ // KeyCache groups by the first `minPrefixLen` chars; it cannot correctly answer queries whose PREFIX is
110
+ // off that grouping width, so those are proxied directly to upstream (a longer prefix would otherwise match
111
+ // on the truncated head and return keys that do not start with the requested prefix — smoldot's
112
+ // `clear_prefix` asserts `key.starts_with(prefix)`).
113
+ //
114
+ // `startKey` is a different matter: every CONTINUATION of a scan carries a full-length storage key by
115
+ // construction, and serving those from the cache is precisely what the cache is for. Bailing out on a long
116
+ // `startKey` makes each continuation page an upstream round-trip.
117
+ //
118
+ // But a long `startKey` is only cache-safe when it belongs to the SAME group as `prefix`. `KeyCache.next()`
119
+ // derives its range from the first `minPrefixLen` chars of the `startKey` alone and never checks the result
120
+ // against `prefix`, so a `startKey` from a different `minPrefixLen`-char group would be answered from that
121
+ // other group's range — returning a key that does not start with `prefix`. `!startKey.startsWith(prefix)`
122
+ // proxies those cross-group requests to upstream; genuine continuations (`startKey.startsWith(prefix)` by
123
+ // construction) still hit the cache. (Reported by @xlc on #1055.)
124
+ if (prefix.length !== minPrefixLen || startKey.length < minPrefixLen || !startKey.startsWith(prefix)) {
112
125
  return this.#api.getKeysPaged(prefix, pageSize, startKey, this.#at);
113
126
  }
114
127
  const startKeyEqualsPrefix = startKey === prefix;
@@ -209,6 +222,11 @@ export class StorageLayer {
209
222
  this.#keys.splice(idx, 1);
210
223
  }
211
224
  }
225
+ #cacheParentValue(key, value) {
226
+ if (!this.#store.has(key) && !this.#deletedPrefix.some((dp)=>key.startsWith(dp))) {
227
+ this.#store.set(key, value);
228
+ }
229
+ }
212
230
  deleted(key) {
213
231
  if (this.#store.has(key)) {
214
232
  return this.#store.get(key) === "Deleted";
@@ -229,9 +247,9 @@ export class StorageLayer {
229
247
  return "Deleted";
230
248
  }
231
249
  if (this.#parent) {
232
- const val = this.#parent.get(key, false);
250
+ const val = await this.#parent.get(key, false);
233
251
  if (cache) {
234
- this.#store.set(key, val);
252
+ this.#cacheParentValue(key, val);
235
253
  }
236
254
  return val;
237
255
  }
@@ -240,9 +258,9 @@ export class StorageLayer {
240
258
  async getMany(keys, cache) {
241
259
  const result = [];
242
260
  const pending = [];
243
- const preloadedPromises = keys.map(async (key, idx)=>{
261
+ keys.forEach((key, idx)=>{
244
262
  if (this.#store.has(key)) {
245
- result[idx] = await this.#store.get(key);
263
+ result[idx] = this.#store.get(key);
246
264
  } else if (this.#deletedPrefix.some((dp)=>key.startsWith(dp))) {
247
265
  result[idx] = "Deleted";
248
266
  } else {
@@ -256,12 +274,11 @@ export class StorageLayer {
256
274
  const vals = await this.#parent.getMany(pending.map((p)=>p.key), false);
257
275
  vals.forEach((val, idx)=>{
258
276
  if (cache) {
259
- this.#store.set(pending[idx].key, val);
277
+ this.#cacheParentValue(pending[idx].key, val);
260
278
  }
261
279
  result[pending[idx].idx] = val;
262
280
  });
263
281
  }
264
- await Promise.all(preloadedPromises);
265
282
  return result;
266
283
  }
267
284
  set(key, value) {
@@ -272,7 +289,7 @@ export class StorageLayer {
272
289
  break;
273
290
  case "DeletedPrefix":
274
291
  this.#deletedPrefix.push(key);
275
- for (const k of this.#keys){
292
+ for (const k of this.#store.keys()){
276
293
  if (k.startsWith(key)) {
277
294
  this.#store.set(k, "Deleted");
278
295
  this.#removeKey(k);
@@ -335,8 +352,7 @@ export class StorageLayer {
335
352
  /**
336
353
  * Merge the storage layer into the given object, can be used to get sotrage diff.
337
354
  */ async mergeInto(into) {
338
- for (const [key, maybeValue] of this.#store){
339
- const value = await maybeValue;
355
+ for (const [key, value] of this.#store){
340
356
  if (value === "Deleted") {
341
357
  into[key] = null;
342
358
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acala-network/chopsticks-core",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "author": "Acala Developers <hello@acala.network>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  "depcheck": "npx depcheck"
15
15
  },
16
16
  "dependencies": {
17
- "@acala-network/chopsticks-executor": "1.5.0",
17
+ "@acala-network/chopsticks-executor": "1.5.2",
18
18
  "@polkadot/rpc-provider": "^16.4.1",
19
19
  "@polkadot/types": "^16.4.1",
20
20
  "@polkadot/types-codec": "^16.4.1",
@@ -35,7 +35,7 @@
35
35
  "@swc/core": "^1.12.14",
36
36
  "@types/lodash": "^4.17.20",
37
37
  "typescript": "^5.8.3",
38
- "vitest": "^4.1.0"
38
+ "vitest": "^4.1.11"
39
39
  },
40
40
  "files": [
41
41
  "dist/esm/**",