@bsv/overlay 2.0.2 → 2.0.4

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 (82) hide show
  1. package/dist/cjs/mod.js +6 -1
  2. package/dist/cjs/mod.js.map +1 -1
  3. package/dist/cjs/package.json +13 -11
  4. package/dist/cjs/src/BASM.js +92 -0
  5. package/dist/cjs/src/BASM.js.map +1 -0
  6. package/dist/cjs/src/BASMRemote.js +43 -0
  7. package/dist/cjs/src/BASMRemote.js.map +1 -0
  8. package/dist/cjs/src/Engine.js +649 -47
  9. package/dist/cjs/src/Engine.js.map +1 -1
  10. package/dist/cjs/src/GASP/OverlayGASPRemote.js +2 -2
  11. package/dist/cjs/src/GASP/OverlayGASPRemote.js.map +1 -1
  12. package/dist/cjs/src/GASP/OverlayGASPStorage.js +18 -25
  13. package/dist/cjs/src/GASP/OverlayGASPStorage.js.map +1 -1
  14. package/dist/cjs/src/storage/knex/KnexStorage.js +329 -12
  15. package/dist/cjs/src/storage/knex/KnexStorage.js.map +1 -1
  16. package/dist/cjs/src/storage/knex/all-migrations.js +3 -1
  17. package/dist/cjs/src/storage/knex/all-migrations.js.map +1 -1
  18. package/dist/cjs/src/storage/knex/migrations/2025-05-28-001-enlarge.js +2 -24
  19. package/dist/cjs/src/storage/knex/migrations/2025-05-28-001-enlarge.js.map +1 -1
  20. package/dist/cjs/src/storage/knex/migrations/2026-05-29-001-brc136-basm.js +114 -0
  21. package/dist/cjs/src/storage/knex/migrations/2026-05-29-001-brc136-basm.js.map +1 -0
  22. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  23. package/dist/esm/mod.js +1 -0
  24. package/dist/esm/mod.js.map +1 -1
  25. package/dist/esm/src/BASM.js +85 -0
  26. package/dist/esm/src/BASM.js.map +1 -0
  27. package/dist/esm/src/BASMRemote.js +42 -0
  28. package/dist/esm/src/BASMRemote.js.map +1 -0
  29. package/dist/esm/src/Engine.js +637 -46
  30. package/dist/esm/src/Engine.js.map +1 -1
  31. package/dist/esm/src/GASP/OverlayGASPRemote.js +2 -2
  32. package/dist/esm/src/GASP/OverlayGASPRemote.js.map +1 -1
  33. package/dist/esm/src/GASP/OverlayGASPStorage.js +18 -25
  34. package/dist/esm/src/GASP/OverlayGASPStorage.js.map +1 -1
  35. package/dist/esm/src/storage/knex/KnexStorage.js +323 -12
  36. package/dist/esm/src/storage/knex/KnexStorage.js.map +1 -1
  37. package/dist/esm/src/storage/knex/all-migrations.js +3 -1
  38. package/dist/esm/src/storage/knex/all-migrations.js.map +1 -1
  39. package/dist/esm/src/storage/knex/migrations/2025-05-28-001-enlarge.js +2 -24
  40. package/dist/esm/src/storage/knex/migrations/2025-05-28-001-enlarge.js.map +1 -1
  41. package/dist/esm/src/storage/knex/migrations/2026-05-29-001-brc136-basm.js +109 -0
  42. package/dist/esm/src/storage/knex/migrations/2026-05-29-001-brc136-basm.js.map +1 -0
  43. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  44. package/dist/types/mod.d.ts +2 -0
  45. package/dist/types/mod.d.ts.map +1 -1
  46. package/dist/types/src/BASM.d.ts +110 -0
  47. package/dist/types/src/BASM.d.ts.map +1 -0
  48. package/dist/types/src/BASMRemote.d.ts +14 -0
  49. package/dist/types/src/BASMRemote.d.ts.map +1 -0
  50. package/dist/types/src/Engine.d.ts +78 -1
  51. package/dist/types/src/Engine.d.ts.map +1 -1
  52. package/dist/types/src/GASP/OverlayGASPStorage.d.ts +1 -1
  53. package/dist/types/src/GASP/OverlayGASPStorage.d.ts.map +1 -1
  54. package/dist/types/src/LookupService.d.ts.map +1 -1
  55. package/dist/types/src/storage/Storage.d.ts +118 -0
  56. package/dist/types/src/storage/Storage.d.ts.map +1 -1
  57. package/dist/types/src/storage/knex/KnexStorage.d.ts +38 -6
  58. package/dist/types/src/storage/knex/KnexStorage.d.ts.map +1 -1
  59. package/dist/types/src/storage/knex/all-migrations.d.ts.map +1 -1
  60. package/dist/types/src/storage/knex/migrations/2025-05-28-001-enlarge.d.ts.map +1 -1
  61. package/dist/types/src/storage/knex/migrations/2026-05-29-001-brc136-basm.d.ts +4 -0
  62. package/dist/types/src/storage/knex/migrations/2026-05-29-001-brc136-basm.d.ts.map +1 -0
  63. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  64. package/docs/BRC-136-BASM.md +285 -0
  65. package/docs/README.md +2 -0
  66. package/docs/Synchronization.md +10 -1
  67. package/mod.ts +25 -1
  68. package/package.json +25 -23
  69. package/src/BASM.ts +208 -0
  70. package/src/BASMRemote.ts +54 -0
  71. package/src/Engine.ts +762 -47
  72. package/src/GASP/OverlayGASPRemote.ts +2 -2
  73. package/src/GASP/OverlayGASPStorage.ts +17 -22
  74. package/src/LookupService.ts +2 -1
  75. package/src/__tests/BASM.test.ts +44 -0
  76. package/src/__tests/BASMChain.test.ts +290 -0
  77. package/src/__tests/Engine.test.ts +3 -4
  78. package/src/storage/Storage.ts +127 -0
  79. package/src/storage/knex/KnexStorage.ts +376 -14
  80. package/src/storage/knex/all-migrations.ts +3 -1
  81. package/src/storage/knex/migrations/2025-05-28-001-enlarge.ts +2 -22
  82. package/src/storage/knex/migrations/2026-05-29-001-brc136-basm.ts +123 -0
@@ -0,0 +1,85 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const BASM_ZERO_HASH = '0000000000000000000000000000000000000000000000000000000000000000';
3
+ function sha256d(buffer) {
4
+ const first = createHash('sha256').update(buffer).digest();
5
+ return createHash('sha256').update(first).digest();
6
+ }
7
+ function assertHashHex(hash, label) {
8
+ if (!/^[0-9a-fA-F]{64}$/.test(hash)) {
9
+ throw new Error(`${label} must be 32 bytes of hex`);
10
+ }
11
+ }
12
+ function displayHexToInternal(hash) {
13
+ assertHashHex(hash, 'hash');
14
+ return Buffer.from(hash, 'hex').reverse();
15
+ }
16
+ function internalToDisplayHex(hash) {
17
+ return Buffer.from(hash).reverse().toString('hex');
18
+ }
19
+ function normalizeAdmittedTxids(admitted) {
20
+ return admitted
21
+ .map((item, originalIndex) => {
22
+ if (typeof item === 'string') {
23
+ return { txid: item, blockIndex: originalIndex };
24
+ }
25
+ return item;
26
+ })
27
+ .sort((a, b) => a.blockIndex - b.blockIndex)
28
+ .map(item => item.txid.toLowerCase());
29
+ }
30
+ /**
31
+ * Computes a BRC-136 BASM root from admitted topic txids.
32
+ *
33
+ * The API accepts normal display-order txid hex because that is what the BSV
34
+ * TypeScript stack exposes at its public boundaries. Hashing is performed on
35
+ * internal byte order as required by the BRC, and the returned root is display
36
+ * order for JSON/wire compatibility.
37
+ */
38
+ export function computeBasmRoot(admitted) {
39
+ const txids = normalizeAdmittedTxids(admitted);
40
+ if (txids.length === 0) {
41
+ return BASM_ZERO_HASH;
42
+ }
43
+ let layer = txids.map(txid => displayHexToInternal(txid));
44
+ if (layer.length === 1) {
45
+ return internalToDisplayHex(layer[0]);
46
+ }
47
+ while (layer.length > 1) {
48
+ const next = [];
49
+ for (let i = 0; i < layer.length; i += 2) {
50
+ const left = layer[i];
51
+ const right = i + 1 < layer.length ? layer[i + 1] : left;
52
+ next.push(sha256d(Buffer.concat([left, right])));
53
+ }
54
+ layer = next;
55
+ }
56
+ return internalToDisplayHex(layer[0]);
57
+ }
58
+ /**
59
+ * Computes the BRC-136 cumulative Topic Anchor Chain hash:
60
+ * SHA256d(prevTac || blockHash || basmRoot), with all inputs reversed to
61
+ * internal byte order before hashing and the output returned as display hex.
62
+ */
63
+ export function computeTac(prevTac, blockHash, basmRoot) {
64
+ const input = Buffer.concat([
65
+ displayHexToInternal(prevTac.toLowerCase()),
66
+ displayHexToInternal(blockHash.toLowerCase()),
67
+ displayHexToInternal(basmRoot.toLowerCase())
68
+ ]);
69
+ return internalToDisplayHex(sha256d(input));
70
+ }
71
+ export function extractMerkleProofMetadata(txid, proof) {
72
+ if (proof === undefined) {
73
+ return undefined;
74
+ }
75
+ const leaf = proof.path[0]?.find(candidate => candidate.hash === txid);
76
+ if (leaf === undefined) {
77
+ return undefined;
78
+ }
79
+ return {
80
+ blockHeight: proof.blockHeight,
81
+ blockIndex: leaf.offset,
82
+ merkleRoot: proof.computeRoot(txid)
83
+ };
84
+ }
85
+ //# sourceMappingURL=BASM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BASM.js","sourceRoot":"","sources":["../../../src/BASM.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ export class BASMRemote {
2
+ endpoint;
3
+ topic;
4
+ fetchImpl;
5
+ constructor(endpoint, topic, fetchImpl = fetch.bind(globalThis)) {
6
+ this.endpoint = endpoint;
7
+ this.topic = topic;
8
+ this.fetchImpl = fetchImpl;
9
+ }
10
+ async requestTopicAnchorTip() {
11
+ return await this.post('/requestTopicAnchorTip', {});
12
+ }
13
+ async requestTopicAnchorRange(fromHeight, toHeight) {
14
+ return await this.post('/requestTopicAnchorRange', { fromHeight, toHeight });
15
+ }
16
+ async requestAdmittedList(blockHeight, blockHash) {
17
+ return await this.post('/requestAdmittedList', { blockHeight, blockHash });
18
+ }
19
+ async requestCompoundMerklePath(blockHeight, txids) {
20
+ return await this.post('/requestCompoundMerklePath', { blockHeight, txids });
21
+ }
22
+ async requestRawTransactions(txids) {
23
+ return await this.post('/requestRawTransactions', { txids });
24
+ }
25
+ async post(path, body) {
26
+ const response = await this.fetchImpl(new URL(path, this.endpoint).toString(), {
27
+ method: 'POST',
28
+ headers: {
29
+ Accept: 'application/json',
30
+ 'Content-Type': 'application/json',
31
+ 'x-bsv-topic': this.topic
32
+ },
33
+ body: JSON.stringify(body)
34
+ });
35
+ const text = await response.text();
36
+ if (!response.ok) {
37
+ throw new Error(`BASM peer ${this.endpoint} returned ${response.status}: ${text}`);
38
+ }
39
+ return (text.length === 0 ? {} : JSON.parse(text));
40
+ }
41
+ }
42
+ //# sourceMappingURL=BASMRemote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BASMRemote.js","sourceRoot":"","sources":["../../../src/BASMRemote.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,UAAU;IAEF;IACA;IACA;IAHnB,YACmB,QAAgB,EAChB,KAAa,EACb,YAA0B,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;QAFhD,aAAQ,GAAR,QAAQ,CAAQ;QAChB,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAuC;IAC/D,CAAC;IAEL,KAAK,CAAC,qBAAqB;QACzB,OAAO,MAAM,IAAI,CAAC,IAAI,CAAiB,wBAAwB,EAAE,EAAE,CAAC,CAAA;IACtE,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,UAAkB,EAAE,QAAgB;QAChE,OAAO,MAAM,IAAI,CAAC,IAAI,CAA2B,0BAA0B,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAA;IACxG,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,WAAmB,EAAE,SAAkB;QAC/D,OAAO,MAAM,IAAI,CAAC,IAAI,CAAuB,sBAAsB,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAA;IAClG,CAAC;IAED,KAAK,CAAC,yBAAyB,CAAC,WAAmB,EAAE,KAAe;QAClE,OAAO,MAAM,IAAI,CAAC,IAAI,CAA6B,4BAA4B,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1G,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,KAAe;QAC1C,OAAO,MAAM,IAAI,CAAC,IAAI,CAAyB,yBAAyB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IACtF,CAAC;IAEO,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAa;QAC/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC7E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,IAAI,CAAC,KAAK;aAC1B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,QAAQ,aAAa,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAA;QACpF,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAM,CAAA;IACzD,CAAC;CACF"}