@typeberry/jam 0.4.1-dae2283 → 0.4.1-f776cce
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/bootstrap-generator.mjs +470 -30
- package/bootstrap-generator.mjs.map +1 -1
- package/bootstrap-importer.mjs +483 -44
- package/bootstrap-importer.mjs.map +1 -1
- package/bootstrap-network.mjs +470 -30
- package/bootstrap-network.mjs.map +1 -1
- package/index.js +483 -44
- package/index.js.map +1 -1
- package/package.json +1 -1
package/bootstrap-importer.mjs
CHANGED
|
@@ -7228,9 +7228,438 @@ class ArrayView {
|
|
|
7228
7228
|
}
|
|
7229
7229
|
}
|
|
7230
7230
|
|
|
7231
|
+
;// CONCATENATED MODULE: ./packages/core/collections/blob-dictionary.ts
|
|
7232
|
+
|
|
7233
|
+
|
|
7234
|
+
/** A map which uses byte blobs as keys */
|
|
7235
|
+
class BlobDictionary extends WithDebug {
|
|
7236
|
+
mapNodeThreshold;
|
|
7237
|
+
/**
|
|
7238
|
+
* The root node of the dictionary.
|
|
7239
|
+
*
|
|
7240
|
+
* This is the main internal data structure that organizes entries
|
|
7241
|
+
* in a tree-like fashion (array-based nodes up to `mapNodeThreshold`,
|
|
7242
|
+
* map-based nodes beyond it). All insertions, updates, and deletions
|
|
7243
|
+
* operate through this structure.
|
|
7244
|
+
*/
|
|
7245
|
+
root = Node.withList();
|
|
7246
|
+
/**
|
|
7247
|
+
* Auxiliary map that stores references to the original keys and their values.
|
|
7248
|
+
*
|
|
7249
|
+
* - Overriding a value in the main structure does not replace the original key reference.
|
|
7250
|
+
* - Used for efficient iteration over `keys()`, `values()`, `entries()`, and computing `size`.
|
|
7251
|
+
*/
|
|
7252
|
+
keyvals = new Map();
|
|
7253
|
+
/**
|
|
7254
|
+
* Protected constructor used internally by `BlobDictionary.new`
|
|
7255
|
+
* and `BlobDictionary.fromEntries`.
|
|
7256
|
+
*
|
|
7257
|
+
* This enforces controlled instantiation — users should create instances
|
|
7258
|
+
* through the provided static factory methods instead of calling the
|
|
7259
|
+
* constructor directly.
|
|
7260
|
+
*
|
|
7261
|
+
* @param mapNodeThreshold - The threshold that determines when the dictionary
|
|
7262
|
+
* switches from using an array-based (`ListChildren`) node to a map-based (`MapChildren`) node for storing entries.
|
|
7263
|
+
*/
|
|
7264
|
+
constructor(mapNodeThreshold) {
|
|
7265
|
+
super();
|
|
7266
|
+
this.mapNodeThreshold = mapNodeThreshold;
|
|
7267
|
+
}
|
|
7268
|
+
/**
|
|
7269
|
+
* Returns the number of entries in the dictionary.
|
|
7270
|
+
*
|
|
7271
|
+
* The count is derived from the auxiliary `keyvals` map, which stores
|
|
7272
|
+
* all original key references and their associated values. This ensures
|
|
7273
|
+
* that the `size` reflects the actual number of entries, independent of
|
|
7274
|
+
* internal overrides in the main `root` structure.
|
|
7275
|
+
*
|
|
7276
|
+
* @returns The total number of entries in the dictionary.
|
|
7277
|
+
*/
|
|
7278
|
+
get size() {
|
|
7279
|
+
return this.keyvals.size;
|
|
7280
|
+
}
|
|
7281
|
+
[TEST_COMPARE_USING]() {
|
|
7282
|
+
const vals = Array.from(this);
|
|
7283
|
+
vals.sort((a, b) => a[0].compare(b[0]).value);
|
|
7284
|
+
return vals;
|
|
7285
|
+
}
|
|
7286
|
+
/**
|
|
7287
|
+
* Creates an empty `BlobDictionary`.
|
|
7288
|
+
*
|
|
7289
|
+
* @param mapNodeThreshold - The threshold that determines when the dictionary
|
|
7290
|
+
* switches from using an array-based (`ListChildren`) node to a map-based (`MapChildren`) node for storing entries.
|
|
7291
|
+
* Defaults to `0`.
|
|
7292
|
+
*
|
|
7293
|
+
* @returns A new, empty `BlobDictionary` instance.
|
|
7294
|
+
*/
|
|
7295
|
+
static new(mapNodeThreshold = 0) {
|
|
7296
|
+
return new BlobDictionary(mapNodeThreshold);
|
|
7297
|
+
}
|
|
7298
|
+
/**
|
|
7299
|
+
* Creates a new `BlobDictionary` initialized with the given entries.
|
|
7300
|
+
*
|
|
7301
|
+
* @param entries - An array of `[key, value]` pairs used to populate the dictionary.
|
|
7302
|
+
* @param mapNodeThreshold - The threshold that determines when the dictionary
|
|
7303
|
+
* switches from using an array-based (`ListChildren`) node to a map-based (`MapChildren`) node for storing entries.
|
|
7304
|
+
* Defaults to `0`.
|
|
7305
|
+
*
|
|
7306
|
+
* @returns A new `BlobDictionary` containing the provided entries.
|
|
7307
|
+
*/
|
|
7308
|
+
static fromEntries(entries, mapNodeThreshold) {
|
|
7309
|
+
const dict = BlobDictionary.new(mapNodeThreshold);
|
|
7310
|
+
for (const [key, value] of entries) {
|
|
7311
|
+
dict.set(key, value);
|
|
7312
|
+
}
|
|
7313
|
+
return dict;
|
|
7314
|
+
}
|
|
7315
|
+
/**
|
|
7316
|
+
* Internal helper that inserts, updates or deletes an entry in the dictionary.
|
|
7317
|
+
*
|
|
7318
|
+
* Behaviour details:
|
|
7319
|
+
* - Passing `undefined` as `value` indicates a deletion. (E.g. `delete` uses `internalSet(key, undefined)`.)
|
|
7320
|
+
* - When an add (new entry) or a delete actually changes the structure, the method returns the affected leaf node.
|
|
7321
|
+
* - When the call only overrides an existing value (no structural add/delete), the method returns `null`.
|
|
7322
|
+
*
|
|
7323
|
+
* This method is intended for internal use by the dictionary implementation and allows `undefined` as a
|
|
7324
|
+
* sentinel value to signal removals.
|
|
7325
|
+
*
|
|
7326
|
+
* @param key - The key to insert, update or remove.
|
|
7327
|
+
* @param value - The value to associate with the key, or `undefined` to remove the key.
|
|
7328
|
+
* @returns The leaf node created or removed on add/delete, or `null` if the operation only overwrote an existing value.
|
|
7329
|
+
*/
|
|
7330
|
+
internalSet(key, value) {
|
|
7331
|
+
let node = this.root;
|
|
7332
|
+
const keyChunkGenerator = key.chunks(CHUNK_SIZE);
|
|
7333
|
+
let depth = 0;
|
|
7334
|
+
for (;;) {
|
|
7335
|
+
const maybeKeyChunk = keyChunkGenerator.next().value;
|
|
7336
|
+
if (maybeKeyChunk === undefined) {
|
|
7337
|
+
if (value === undefined) {
|
|
7338
|
+
return node.remove(key);
|
|
7339
|
+
}
|
|
7340
|
+
return node.set(key, value);
|
|
7341
|
+
}
|
|
7342
|
+
const keyChunk = opaque_asOpaqueType(maybeKeyChunk);
|
|
7343
|
+
if (node.children instanceof ListChildren) {
|
|
7344
|
+
const subkey = bytes_BytesBlob.blobFrom(key.raw.subarray(CHUNK_SIZE * depth));
|
|
7345
|
+
const leaf = value !== undefined ? node.children.insert(subkey, { key, value }) : node.children.remove(subkey);
|
|
7346
|
+
if (subkey.length > CHUNK_SIZE && node.children.children.length > this.mapNodeThreshold) {
|
|
7347
|
+
node.convertListChildrenToMap();
|
|
7348
|
+
}
|
|
7349
|
+
return leaf;
|
|
7350
|
+
}
|
|
7351
|
+
depth += 1;
|
|
7352
|
+
const children = node.children;
|
|
7353
|
+
if (children instanceof ListChildren) {
|
|
7354
|
+
throw new Error("We handle list node earlier. If we fall through, we know it's for the `Map` case.");
|
|
7355
|
+
}
|
|
7356
|
+
if (children instanceof MapChildren) {
|
|
7357
|
+
const maybeNode = children.getChild(keyChunk);
|
|
7358
|
+
if (maybeNode !== undefined) {
|
|
7359
|
+
// simply go one level deeper
|
|
7360
|
+
node = maybeNode;
|
|
7361
|
+
}
|
|
7362
|
+
else {
|
|
7363
|
+
// we are trying to remove an item, but it does not exist
|
|
7364
|
+
if (value === undefined) {
|
|
7365
|
+
return null;
|
|
7366
|
+
}
|
|
7367
|
+
// no more child nodes, we insert a new one.
|
|
7368
|
+
const newNode = Node.withList();
|
|
7369
|
+
children.setChild(keyChunk, newNode);
|
|
7370
|
+
node = newNode;
|
|
7371
|
+
}
|
|
7372
|
+
continue;
|
|
7373
|
+
}
|
|
7374
|
+
assertNever(children);
|
|
7375
|
+
}
|
|
7376
|
+
}
|
|
7377
|
+
/**
|
|
7378
|
+
* Adds a new entry to the dictionary or updates the value of an existing key.
|
|
7379
|
+
*
|
|
7380
|
+
* If an entry with the given key already exists, its value is replaced
|
|
7381
|
+
* with the new one.
|
|
7382
|
+
*
|
|
7383
|
+
* @param key - The key to add or update in the dictionary.
|
|
7384
|
+
* @param value - The value to associate with the specified key.
|
|
7385
|
+
* @returns Nothing (`void`).
|
|
7386
|
+
*/
|
|
7387
|
+
set(key, value) {
|
|
7388
|
+
const leaf = this.internalSet(key, value);
|
|
7389
|
+
if (leaf !== null) {
|
|
7390
|
+
this.keyvals.set(leaf.key, leaf);
|
|
7391
|
+
}
|
|
7392
|
+
}
|
|
7393
|
+
/**
|
|
7394
|
+
* Retrieves the value associated with the given key from the dictionary.
|
|
7395
|
+
*
|
|
7396
|
+
* If the key does not exist, this method returns `undefined`.
|
|
7397
|
+
*
|
|
7398
|
+
* @param key - The key whose associated value should be retrieved.
|
|
7399
|
+
* @returns The value associated with the specified key, or `undefined` if the key is not present.
|
|
7400
|
+
*/
|
|
7401
|
+
get(key) {
|
|
7402
|
+
let node = this.root;
|
|
7403
|
+
const pathChunksGenerator = key.chunks(CHUNK_SIZE);
|
|
7404
|
+
let depth = 0;
|
|
7405
|
+
while (node !== undefined) {
|
|
7406
|
+
const maybePathChunk = pathChunksGenerator.next().value;
|
|
7407
|
+
if (node.children instanceof ListChildren) {
|
|
7408
|
+
const subkey = bytes_BytesBlob.blobFrom(key.raw.subarray(depth * CHUNK_SIZE));
|
|
7409
|
+
const child = node.children.find(subkey);
|
|
7410
|
+
if (child !== null) {
|
|
7411
|
+
return child.value;
|
|
7412
|
+
}
|
|
7413
|
+
}
|
|
7414
|
+
if (maybePathChunk === undefined) {
|
|
7415
|
+
return node.getLeaf()?.value;
|
|
7416
|
+
}
|
|
7417
|
+
if (node.children instanceof MapChildren) {
|
|
7418
|
+
const pathChunk = opaque_asOpaqueType(maybePathChunk);
|
|
7419
|
+
node = node.children.getChild(pathChunk);
|
|
7420
|
+
depth += 1;
|
|
7421
|
+
}
|
|
7422
|
+
}
|
|
7423
|
+
return undefined;
|
|
7424
|
+
}
|
|
7425
|
+
/**
|
|
7426
|
+
* Checks whether the dictionary contains an entry for the given key.
|
|
7427
|
+
*
|
|
7428
|
+
* ⚠️ **Note:** Avoid using `has(...)` together with `get(...)` in a pattern like this:
|
|
7429
|
+
*
|
|
7430
|
+
* ```ts
|
|
7431
|
+
* if (dict.has(key)) {
|
|
7432
|
+
* const value = dict.get(key);
|
|
7433
|
+
* ...
|
|
7434
|
+
* }
|
|
7435
|
+
* ```
|
|
7436
|
+
*
|
|
7437
|
+
* This approach performs two lookups for the same key.
|
|
7438
|
+
*
|
|
7439
|
+
* Instead, prefer the following pattern, which retrieves the value once:
|
|
7440
|
+
*
|
|
7441
|
+
* ```ts
|
|
7442
|
+
* const value = dict.get(key);
|
|
7443
|
+
* if (value !== undefined) {
|
|
7444
|
+
* ...
|
|
7445
|
+
* }
|
|
7446
|
+
* ```
|
|
7447
|
+
*
|
|
7448
|
+
* @param key - The key to check for.
|
|
7449
|
+
* @returns `true` if the dictionary contains an entry for the given key, otherwise `false`.
|
|
7450
|
+
*/
|
|
7451
|
+
has(key) {
|
|
7452
|
+
return this.get(key) !== undefined;
|
|
7453
|
+
}
|
|
7454
|
+
/**
|
|
7455
|
+
* Removes an entry with the specified key from the dictionary.
|
|
7456
|
+
*
|
|
7457
|
+
* Internally, this calls {@link internalSet} with `undefined` to mark the entry as deleted.
|
|
7458
|
+
*
|
|
7459
|
+
* @param key - The key of the entry to remove.
|
|
7460
|
+
* @returns `true` if an entry was removed (i.e. the key existed), otherwise `false`.
|
|
7461
|
+
*/
|
|
7462
|
+
delete(key) {
|
|
7463
|
+
const leaf = this.internalSet(key, undefined);
|
|
7464
|
+
if (leaf !== null) {
|
|
7465
|
+
this.keyvals.delete(leaf.key);
|
|
7466
|
+
return true;
|
|
7467
|
+
}
|
|
7468
|
+
return false;
|
|
7469
|
+
}
|
|
7470
|
+
/**
|
|
7471
|
+
* Returns an iterator over the keys in the dictionary.
|
|
7472
|
+
*
|
|
7473
|
+
* The iterator yields each key in insertion order.
|
|
7474
|
+
*
|
|
7475
|
+
* @returns An iterator over all keys in the dictionary.
|
|
7476
|
+
*/
|
|
7477
|
+
keys() {
|
|
7478
|
+
return this.keyvals.keys();
|
|
7479
|
+
}
|
|
7480
|
+
/**
|
|
7481
|
+
* Returns an iterator over the values in the dictionary.
|
|
7482
|
+
*
|
|
7483
|
+
* The iterator yields each value in insertion order.
|
|
7484
|
+
*
|
|
7485
|
+
* @returns An iterator over all values in the dictionary.
|
|
7486
|
+
*/
|
|
7487
|
+
*values() {
|
|
7488
|
+
for (const leaf of this.keyvals.values()) {
|
|
7489
|
+
yield leaf.value;
|
|
7490
|
+
}
|
|
7491
|
+
}
|
|
7492
|
+
/**
|
|
7493
|
+
* Returns an iterator over the `[key, value]` pairs in the dictionary.
|
|
7494
|
+
*
|
|
7495
|
+
* The iterator yields entries in insertion order.
|
|
7496
|
+
*
|
|
7497
|
+
* @returns An iterator over `[key, value]` tuples for each entry in the dictionary.
|
|
7498
|
+
*/
|
|
7499
|
+
*entries() {
|
|
7500
|
+
for (const leaf of this.keyvals.values()) {
|
|
7501
|
+
yield [leaf.key, leaf.value];
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
/**
|
|
7505
|
+
* Default iterator for the dictionary.
|
|
7506
|
+
*
|
|
7507
|
+
* Equivalent to calling {@link entries}.
|
|
7508
|
+
* Enables iteration with `for...of`:
|
|
7509
|
+
*
|
|
7510
|
+
* ```ts
|
|
7511
|
+
* for (const [key, value] of dict) {
|
|
7512
|
+
* ...
|
|
7513
|
+
* }
|
|
7514
|
+
* ```
|
|
7515
|
+
*
|
|
7516
|
+
* @returns An iterator over `[key, value]` pairs.
|
|
7517
|
+
*/
|
|
7518
|
+
[Symbol.iterator]() {
|
|
7519
|
+
return this.entries();
|
|
7520
|
+
}
|
|
7521
|
+
/**
|
|
7522
|
+
* Creates a new sorted array of values, ordered by their corresponding keys.
|
|
7523
|
+
*
|
|
7524
|
+
* Iterates over all entries in the dictionary and sorts them according
|
|
7525
|
+
* to the provided comparator function applied to the keys.
|
|
7526
|
+
*
|
|
7527
|
+
* @param comparator - A comparator function that can compare two keys.
|
|
7528
|
+
*
|
|
7529
|
+
* @returns A new array containing all values from the dictionary,
|
|
7530
|
+
* sorted according to their keys.
|
|
7531
|
+
*/
|
|
7532
|
+
toSortedArray(comparator) {
|
|
7533
|
+
const vals = Array.from(this);
|
|
7534
|
+
vals.sort((a, b) => comparator(a[0], b[0]).value);
|
|
7535
|
+
return vals.map((x) => x[1]);
|
|
7536
|
+
}
|
|
7537
|
+
}
|
|
7538
|
+
const CHUNK_SIZE = 6;
|
|
7539
|
+
/**
|
|
7540
|
+
* A function to transform a bytes chunk (up to 6 bytes into U48 number)
|
|
7541
|
+
*
|
|
7542
|
+
* Note that it uses 3 additional bits to store length(`value * 8 + len;`),
|
|
7543
|
+
* It is needed to distinguish shorter chunks that have 0s at the end, for example: [1, 2] and [1, 2, 0]
|
|
7544
|
+
* */
|
|
7545
|
+
function bytesAsU48(bytes) {
|
|
7546
|
+
const len = bytes.length;
|
|
7547
|
+
debug_check `${len <= CHUNK_SIZE} Length has to be <= ${CHUNK_SIZE}, got: ${len}`;
|
|
7548
|
+
let value = bytes[3] | (bytes[2] << 8) | (bytes[1] << 16) | (bytes[0] << 24);
|
|
7549
|
+
for (let i = 4; i < bytes.length; i++) {
|
|
7550
|
+
value = value * 256 + bytes[i];
|
|
7551
|
+
}
|
|
7552
|
+
return value * 8 + len;
|
|
7553
|
+
}
|
|
7554
|
+
class Node {
|
|
7555
|
+
leaf;
|
|
7556
|
+
children;
|
|
7557
|
+
convertListChildrenToMap() {
|
|
7558
|
+
if (!(this.children instanceof ListChildren)) {
|
|
7559
|
+
return;
|
|
7560
|
+
}
|
|
7561
|
+
this.children = MapChildren.fromListNode(this.children);
|
|
7562
|
+
}
|
|
7563
|
+
static withList() {
|
|
7564
|
+
return new Node(undefined, ListChildren.new());
|
|
7565
|
+
}
|
|
7566
|
+
static withMap() {
|
|
7567
|
+
return new Node(undefined, MapChildren.new());
|
|
7568
|
+
}
|
|
7569
|
+
constructor(leaf, children) {
|
|
7570
|
+
this.leaf = leaf;
|
|
7571
|
+
this.children = children;
|
|
7572
|
+
}
|
|
7573
|
+
getLeaf() {
|
|
7574
|
+
return this.leaf;
|
|
7575
|
+
}
|
|
7576
|
+
remove(_key) {
|
|
7577
|
+
if (this.leaf === undefined) {
|
|
7578
|
+
return null;
|
|
7579
|
+
}
|
|
7580
|
+
const removedLeaf = this.leaf;
|
|
7581
|
+
this.leaf = undefined;
|
|
7582
|
+
return removedLeaf;
|
|
7583
|
+
}
|
|
7584
|
+
set(key, value) {
|
|
7585
|
+
if (this.leaf === undefined) {
|
|
7586
|
+
this.leaf = { key, value };
|
|
7587
|
+
return this.leaf;
|
|
7588
|
+
}
|
|
7589
|
+
this.leaf.value = value;
|
|
7590
|
+
return null;
|
|
7591
|
+
}
|
|
7592
|
+
}
|
|
7593
|
+
class ListChildren {
|
|
7594
|
+
children = [];
|
|
7595
|
+
constructor() { }
|
|
7596
|
+
find(key) {
|
|
7597
|
+
const result = this.children.find((item) => item[0].isEqualTo(key));
|
|
7598
|
+
if (result !== undefined) {
|
|
7599
|
+
return result[1];
|
|
7600
|
+
}
|
|
7601
|
+
return null;
|
|
7602
|
+
}
|
|
7603
|
+
remove(key) {
|
|
7604
|
+
const existingIndex = this.children.findIndex((item) => item[0].isEqualTo(key));
|
|
7605
|
+
if (existingIndex >= 0) {
|
|
7606
|
+
const ret = this.children.splice(existingIndex, 1);
|
|
7607
|
+
return ret[0][1];
|
|
7608
|
+
}
|
|
7609
|
+
return null;
|
|
7610
|
+
}
|
|
7611
|
+
insert(key, leaf) {
|
|
7612
|
+
const existingIndex = this.children.findIndex((item) => item[0].isEqualTo(key));
|
|
7613
|
+
if (existingIndex >= 0) {
|
|
7614
|
+
const existing = this.children[existingIndex];
|
|
7615
|
+
existing[1].value = leaf.value;
|
|
7616
|
+
return null;
|
|
7617
|
+
}
|
|
7618
|
+
this.children.push([key, leaf]);
|
|
7619
|
+
return leaf;
|
|
7620
|
+
}
|
|
7621
|
+
static new() {
|
|
7622
|
+
return new ListChildren();
|
|
7623
|
+
}
|
|
7624
|
+
}
|
|
7625
|
+
class MapChildren {
|
|
7626
|
+
children = new Map();
|
|
7627
|
+
constructor() { }
|
|
7628
|
+
static new() {
|
|
7629
|
+
return new MapChildren();
|
|
7630
|
+
}
|
|
7631
|
+
static fromListNode(node) {
|
|
7632
|
+
const mapNode = new MapChildren();
|
|
7633
|
+
for (const [key, leaf] of node.children) {
|
|
7634
|
+
const currentKeyChunk = opaque_asOpaqueType(bytes_BytesBlob.blobFrom(key.raw.subarray(0, CHUNK_SIZE)));
|
|
7635
|
+
const subKey = bytes_BytesBlob.blobFrom(key.raw.subarray(CHUNK_SIZE));
|
|
7636
|
+
let child = mapNode.getChild(currentKeyChunk);
|
|
7637
|
+
if (child === undefined) {
|
|
7638
|
+
child = Node.withList();
|
|
7639
|
+
mapNode.setChild(currentKeyChunk, child);
|
|
7640
|
+
}
|
|
7641
|
+
const children = child.children;
|
|
7642
|
+
children.insert(subKey, leaf);
|
|
7643
|
+
}
|
|
7644
|
+
return mapNode;
|
|
7645
|
+
}
|
|
7646
|
+
getChild(keyChunk) {
|
|
7647
|
+
const chunkAsNumber = bytesAsU48(keyChunk.raw);
|
|
7648
|
+
return this.children.get(chunkAsNumber);
|
|
7649
|
+
}
|
|
7650
|
+
setChild(keyChunk, node) {
|
|
7651
|
+
const chunkAsNumber = bytesAsU48(keyChunk.raw);
|
|
7652
|
+
this.children.set(chunkAsNumber, node);
|
|
7653
|
+
}
|
|
7654
|
+
}
|
|
7655
|
+
|
|
7231
7656
|
;// CONCATENATED MODULE: ./packages/core/collections/hash-dictionary.ts
|
|
7232
|
-
/**
|
|
7233
|
-
|
|
7657
|
+
/**
|
|
7658
|
+
* A map which uses hashes as keys.
|
|
7659
|
+
*
|
|
7660
|
+
* @deprecated
|
|
7661
|
+
* */
|
|
7662
|
+
class StringHashDictionary {
|
|
7234
7663
|
// TODO [ToDr] [crit] We can't use `TrieHash` directly in the map,
|
|
7235
7664
|
// because of the way it's being compared. Hence having `string` here.
|
|
7236
7665
|
// This has to be benchmarked and re-written to a custom map most likely.
|
|
@@ -7296,6 +7725,17 @@ class hash_dictionary_HashDictionary {
|
|
|
7296
7725
|
}
|
|
7297
7726
|
}
|
|
7298
7727
|
|
|
7728
|
+
/**
|
|
7729
|
+
* A value that indicates when `BlobDictionary` transforms Array nodes into Map nodes.
|
|
7730
|
+
* In practice, it doesn't matter much because, in real life, arrays in this structure usually have a length close to 1.
|
|
7731
|
+
*/
|
|
7732
|
+
const BLOB_DICTIONARY_THRESHOLD = 5;
|
|
7733
|
+
class hash_dictionary_HashDictionary extends BlobDictionary {
|
|
7734
|
+
constructor() {
|
|
7735
|
+
super(BLOB_DICTIONARY_THRESHOLD);
|
|
7736
|
+
}
|
|
7737
|
+
}
|
|
7738
|
+
|
|
7299
7739
|
;// CONCATENATED MODULE: ./packages/core/collections/hash-set.ts
|
|
7300
7740
|
|
|
7301
7741
|
/** A set specialized for storing hashes. */
|
|
@@ -7760,6 +8200,18 @@ class SortedSet extends SortedArray {
|
|
|
7760
8200
|
|
|
7761
8201
|
|
|
7762
8202
|
|
|
8203
|
+
function getTruncatedKey(key) {
|
|
8204
|
+
// Always return exactly TRUNCATED_HASH_SIZE bytes.
|
|
8205
|
+
if (key.length === TRUNCATED_HASH_SIZE) {
|
|
8206
|
+
return key;
|
|
8207
|
+
}
|
|
8208
|
+
return bytes_Bytes.fromBlob(key.raw.subarray(0, TRUNCATED_HASH_SIZE), TRUNCATED_HASH_SIZE);
|
|
8209
|
+
}
|
|
8210
|
+
/**
|
|
8211
|
+
* A value that indicates when `BlobDictionary` transforms Array nodes into Map nodes.
|
|
8212
|
+
* In practice, it doesn't matter much because, in real life, arrays in this structure usually have a length close to 1.
|
|
8213
|
+
*/
|
|
8214
|
+
const truncated_hash_dictionary_BLOB_DICTIONARY_THRESHOLD = 5;
|
|
7763
8215
|
/**
|
|
7764
8216
|
* A collection of hash-based keys (likely `StateKey`s) which ignores
|
|
7765
8217
|
* differences on the last byte.
|
|
@@ -7772,48 +8224,37 @@ class TruncatedHashDictionary {
|
|
|
7772
8224
|
* Each key will be copied and have the last byte replace with a 0.
|
|
7773
8225
|
*/
|
|
7774
8226
|
static fromEntries(entries) {
|
|
7775
|
-
|
|
7776
|
-
const mapped = Array.from(entries).map(([key, value]) => {
|
|
7777
|
-
const newKey = bytes_Bytes.zero(hash_HASH_SIZE).asOpaque();
|
|
7778
|
-
newKey.raw.set(key.raw.subarray(0, TRUNCATED_HASH_SIZE));
|
|
7779
|
-
return [newKey, value];
|
|
7780
|
-
});
|
|
7781
|
-
return new TruncatedHashDictionary(hash_dictionary_HashDictionary.fromEntries(mapped));
|
|
8227
|
+
return new TruncatedHashDictionary(BlobDictionary.fromEntries(Array.from(entries).map(([key, value]) => [getTruncatedKey(key), value]), truncated_hash_dictionary_BLOB_DICTIONARY_THRESHOLD));
|
|
7782
8228
|
}
|
|
7783
|
-
/** A truncated key which we re-use to query the dictionary. */
|
|
7784
|
-
truncatedKey = bytes_Bytes.zero(hash_HASH_SIZE).asOpaque();
|
|
7785
8229
|
constructor(dict) {
|
|
7786
8230
|
this.dict = dict;
|
|
7787
8231
|
}
|
|
7788
8232
|
[TEST_COMPARE_USING]() {
|
|
7789
|
-
return this.dict;
|
|
8233
|
+
return Array.from(this.dict);
|
|
7790
8234
|
}
|
|
7791
8235
|
/** Return number of items in the dictionary. */
|
|
7792
8236
|
get size() {
|
|
7793
8237
|
return this.dict.size;
|
|
7794
8238
|
}
|
|
7795
8239
|
/** Retrieve a value that matches the key on `TRUNCATED_HASH_SIZE`. */
|
|
7796
|
-
get(
|
|
7797
|
-
|
|
7798
|
-
return this.dict.get(
|
|
8240
|
+
get(key) {
|
|
8241
|
+
const truncatedKey = getTruncatedKey(key);
|
|
8242
|
+
return this.dict.get(truncatedKey);
|
|
7799
8243
|
}
|
|
7800
8244
|
/** Return true if the key is present in the dictionary */
|
|
7801
|
-
has(
|
|
7802
|
-
|
|
7803
|
-
return this.dict.has(
|
|
8245
|
+
has(key) {
|
|
8246
|
+
const truncatedKey = getTruncatedKey(key);
|
|
8247
|
+
return this.dict.has(truncatedKey);
|
|
7804
8248
|
}
|
|
7805
8249
|
/** Set or update a value that matches the key on `TRUNCATED_HASH_SIZE`. */
|
|
7806
|
-
set(
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
const key = bytes_Bytes.zero(hash_HASH_SIZE);
|
|
7810
|
-
key.raw.set(fullKey.raw.subarray(0, TRUNCATED_HASH_SIZE));
|
|
7811
|
-
this.dict.set(key.asOpaque(), value);
|
|
8250
|
+
set(key, value) {
|
|
8251
|
+
const truncatedKey = getTruncatedKey(key);
|
|
8252
|
+
this.dict.set(truncatedKey, value);
|
|
7812
8253
|
}
|
|
7813
8254
|
/** Remove a value that matches the key on `TRUNCATED_HASH_SIZE`. */
|
|
7814
|
-
delete(
|
|
7815
|
-
|
|
7816
|
-
this.dict.delete(
|
|
8255
|
+
delete(key) {
|
|
8256
|
+
const truncatedKey = getTruncatedKey(key);
|
|
8257
|
+
this.dict.delete(truncatedKey);
|
|
7817
8258
|
}
|
|
7818
8259
|
/** Iterator over values of the dictionary. */
|
|
7819
8260
|
values() {
|
|
@@ -7821,9 +8262,7 @@ class TruncatedHashDictionary {
|
|
|
7821
8262
|
}
|
|
7822
8263
|
/** Iterator over entries of the dictionary (with truncated keys) */
|
|
7823
8264
|
*entries() {
|
|
7824
|
-
|
|
7825
|
-
yield [bytes_Bytes.fromBlob(key.raw.subarray(0, TRUNCATED_HASH_SIZE), TRUNCATED_HASH_SIZE).asOpaque(), value];
|
|
7826
|
-
}
|
|
8265
|
+
yield* this.dict.entries();
|
|
7827
8266
|
}
|
|
7828
8267
|
[Symbol.iterator]() {
|
|
7829
8268
|
return this.entries();
|
|
@@ -7840,6 +8279,7 @@ class TruncatedHashDictionary {
|
|
|
7840
8279
|
|
|
7841
8280
|
|
|
7842
8281
|
|
|
8282
|
+
|
|
7843
8283
|
;// CONCATENATED MODULE: ./packages/jam/config/chain-spec.ts
|
|
7844
8284
|
|
|
7845
8285
|
|
|
@@ -11371,7 +11811,7 @@ class BlockVerifier {
|
|
|
11371
11811
|
this.hasher = hasher;
|
|
11372
11812
|
this.blocks = blocks;
|
|
11373
11813
|
}
|
|
11374
|
-
async verifyBlock(block) {
|
|
11814
|
+
async verifyBlock(block, options = { skipParentAndStateRoot: false }) {
|
|
11375
11815
|
const headerView = block.header.view();
|
|
11376
11816
|
const headerHash = this.hasher.header(headerView);
|
|
11377
11817
|
// check if current block is already imported
|
|
@@ -11383,7 +11823,7 @@ class BlockVerifier {
|
|
|
11383
11823
|
// https://graypaper.fluffylabs.dev/#/cc517d7/0c9d000c9d00?v=0.6.5
|
|
11384
11824
|
const parentHash = headerView.parentHeaderHash.materialize();
|
|
11385
11825
|
// importing genesis block
|
|
11386
|
-
if (!parentHash.isEqualTo(block_verifier_ZERO_HASH)) {
|
|
11826
|
+
if (!parentHash.isEqualTo(block_verifier_ZERO_HASH) && !options.skipParentAndStateRoot) {
|
|
11387
11827
|
const parentBlock = this.blocks.getHeader(parentHash);
|
|
11388
11828
|
if (parentBlock === null) {
|
|
11389
11829
|
return Result.error(BlockVerifierError.ParentNotFound, () => `Parent ${parentHash.toString()} not found`);
|
|
@@ -11403,21 +11843,20 @@ class BlockVerifier {
|
|
|
11403
11843
|
if (!extrinsicHash.isEqualTo(extrinsicMerkleCommitment.hash)) {
|
|
11404
11844
|
return Result.error(BlockVerifierError.InvalidExtrinsic, () => `Invalid extrinsic hash: ${extrinsicHash.toString()}, expected ${extrinsicMerkleCommitment.hash.toString()}`);
|
|
11405
11845
|
}
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11846
|
+
if (!options.skipParentAndStateRoot) {
|
|
11847
|
+
// Check if the state root is valid.
|
|
11848
|
+
// https://graypaper.fluffylabs.dev/#/ab2cdbd/0c73010c7301?v=0.7.2
|
|
11849
|
+
const stateRoot = headerView.priorStateRoot.materialize();
|
|
11850
|
+
const posteriorStateRoot = this.blocks.getPostStateRoot(parentHash);
|
|
11851
|
+
if (posteriorStateRoot === null) {
|
|
11852
|
+
return Result.error(BlockVerifierError.StateRootNotFound, () => `Posterior state root ${parentHash.toString()} not found`);
|
|
11853
|
+
}
|
|
11854
|
+
if (!stateRoot.isEqualTo(posteriorStateRoot)) {
|
|
11855
|
+
return Result.error(BlockVerifierError.InvalidStateRoot, () => `Invalid prior state root: ${stateRoot.toString()}, expected ${posteriorStateRoot.toString()} (ours)`);
|
|
11856
|
+
}
|
|
11415
11857
|
}
|
|
11416
11858
|
return Result.ok(headerHash.hash);
|
|
11417
11859
|
}
|
|
11418
|
-
hashHeader(block) {
|
|
11419
|
-
return this.hasher.header(block.header.view());
|
|
11420
|
-
}
|
|
11421
11860
|
}
|
|
11422
11861
|
|
|
11423
11862
|
;// CONCATENATED MODULE: ./packages/jam/transition/disputes/disputes-error-code.ts
|