@bsv/overlay 2.3.1 → 2.6.1
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/README.md +166 -0
- package/dist/cjs/mod.d.ts +3 -0
- package/dist/cjs/mod.d.ts.map +1 -1
- package/dist/cjs/mod.js +8 -1
- package/dist/cjs/mod.js.map +1 -1
- package/dist/cjs/package.json +10 -4
- package/dist/cjs/src/BASM.d.ts +6 -0
- package/dist/cjs/src/BASM.d.ts.map +1 -1
- package/dist/cjs/src/BASM.js +21 -8
- package/dist/cjs/src/BASM.js.map +1 -1
- package/dist/cjs/src/BASMRemote.d.ts +8 -1
- package/dist/cjs/src/BASMRemote.d.ts.map +1 -1
- package/dist/cjs/src/BASMRemote.js +179 -13
- package/dist/cjs/src/BASMRemote.js.map +1 -1
- package/dist/cjs/src/BASMValidation.d.ts +27 -0
- package/dist/cjs/src/BASMValidation.d.ts.map +1 -0
- package/dist/cjs/src/BASMValidation.js +108 -0
- package/dist/cjs/src/BASMValidation.js.map +1 -0
- package/dist/cjs/src/DiscoveryAdvertisementValidation.d.ts +11 -0
- package/dist/cjs/src/DiscoveryAdvertisementValidation.d.ts.map +1 -0
- package/dist/cjs/src/DiscoveryAdvertisementValidation.js +60 -0
- package/dist/cjs/src/DiscoveryAdvertisementValidation.js.map +1 -0
- package/dist/cjs/src/Engine.d.ts +37 -13
- package/dist/cjs/src/Engine.d.ts.map +1 -1
- package/dist/cjs/src/Engine.js +1713 -336
- package/dist/cjs/src/Engine.js.map +1 -1
- package/dist/cjs/src/EngineAdmission.d.ts +70 -0
- package/dist/cjs/src/EngineAdmission.d.ts.map +1 -0
- package/dist/cjs/src/EngineAdmission.js +297 -0
- package/dist/cjs/src/EngineAdmission.js.map +1 -0
- package/dist/cjs/src/GASP/OverlayGASPRemote.d.ts +4 -3
- package/dist/cjs/src/GASP/OverlayGASPRemote.d.ts.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPRemote.js +27 -43
- package/dist/cjs/src/GASP/OverlayGASPRemote.js.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPStorage.d.ts +22 -16
- package/dist/cjs/src/GASP/OverlayGASPStorage.d.ts.map +1 -1
- package/dist/cjs/src/GASP/OverlayGASPStorage.js +206 -57
- package/dist/cjs/src/GASP/OverlayGASPStorage.js.map +1 -1
- package/dist/cjs/src/RemoteSecurity.d.ts +50 -0
- package/dist/cjs/src/RemoteSecurity.d.ts.map +1 -0
- package/dist/cjs/src/RemoteSecurity.js +301 -0
- package/dist/cjs/src/RemoteSecurity.js.map +1 -0
- package/dist/cjs/src/storage/AdmissionStorage.d.ts +185 -0
- package/dist/cjs/src/storage/AdmissionStorage.d.ts.map +1 -0
- package/dist/cjs/src/storage/AdmissionStorage.js +93 -0
- package/dist/cjs/src/storage/AdmissionStorage.js.map +1 -0
- package/dist/cjs/src/storage/RecoveryContract.d.ts +50 -0
- package/dist/cjs/src/storage/RecoveryContract.d.ts.map +1 -0
- package/dist/cjs/src/storage/RecoveryContract.js +35 -0
- package/dist/cjs/src/storage/RecoveryContract.js.map +1 -0
- package/dist/cjs/src/storage/Storage.d.ts +32 -19
- package/dist/cjs/src/storage/Storage.d.ts.map +1 -1
- package/dist/cjs/src/storage/Storage.js +5 -0
- package/dist/cjs/src/storage/Storage.js.map +1 -1
- package/dist/cjs/src/storage/knex/KnexStorage.d.ts +8 -8
- package/dist/cjs/src/storage/knex/KnexStorage.d.ts.map +1 -1
- package/dist/cjs/src/storage/knex/KnexStorage.js +98 -61
- package/dist/cjs/src/storage/knex/KnexStorage.js.map +1 -1
- package/dist/cjs/src/storage/knex/all-migrations.d.ts.map +1 -1
- package/dist/cjs/src/storage/knex/all-migrations.js +5 -1
- package/dist/cjs/src/storage/knex/all-migrations.js.map +1 -1
- package/dist/cjs/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.d.ts +4 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.d.ts.map +1 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.js +36 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.js.map +1 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-20-001-spent-by.d.ts +5 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-20-001-spent-by.d.ts.map +1 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-20-001-spent-by.js +16 -0
- package/dist/cjs/src/storage/knex/migrations/2026-09-20-001-spent-by.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionPlan.d.ts +18 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionPlan.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionPlan.js +229 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionPlan.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionStorage.d.ts +112 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionStorage.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionStorage.js +675 -0
- package/dist/cjs/src/storage/mongo/MongoAdmissionStorage.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoOverlayStorage.d.ts +71 -0
- package/dist/cjs/src/storage/mongo/MongoOverlayStorage.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoOverlayStorage.js +453 -0
- package/dist/cjs/src/storage/mongo/MongoOverlayStorage.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoPayloadStore.d.ts +134 -0
- package/dist/cjs/src/storage/mongo/MongoPayloadStore.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoPayloadStore.js +756 -0
- package/dist/cjs/src/storage/mongo/MongoPayloadStore.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoReadGuards.d.ts +44 -0
- package/dist/cjs/src/storage/mongo/MongoReadGuards.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoReadGuards.js +135 -0
- package/dist/cjs/src/storage/mongo/MongoReadGuards.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoSchema.d.ts +67 -0
- package/dist/cjs/src/storage/mongo/MongoSchema.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoSchema.js +743 -0
- package/dist/cjs/src/storage/mongo/MongoSchema.js.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoTransactionRunner.d.ts +69 -0
- package/dist/cjs/src/storage/mongo/MongoTransactionRunner.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo/MongoTransactionRunner.js +368 -0
- package/dist/cjs/src/storage/mongo/MongoTransactionRunner.js.map +1 -0
- package/dist/cjs/src/storage/mongo.d.ts +9 -0
- package/dist/cjs/src/storage/mongo.d.ts.map +1 -0
- package/dist/cjs/src/storage/mongo.js +25 -0
- package/dist/cjs/src/storage/mongo.js.map +1 -0
- package/dist/esm/mod.js +3 -0
- package/dist/esm/mod.js.map +1 -1
- package/dist/esm/src/BASM.js +21 -8
- package/dist/esm/src/BASM.js.map +1 -1
- package/dist/esm/src/BASMRemote.js +176 -12
- package/dist/esm/src/BASMRemote.js.map +1 -1
- package/dist/esm/src/BASMValidation.js +95 -0
- package/dist/esm/src/BASMValidation.js.map +1 -0
- package/dist/esm/src/DiscoveryAdvertisementValidation.js +57 -0
- package/dist/esm/src/DiscoveryAdvertisementValidation.js.map +1 -0
- package/dist/esm/src/Engine.js +1698 -326
- package/dist/esm/src/Engine.js.map +1 -1
- package/dist/esm/src/EngineAdmission.js +280 -0
- package/dist/esm/src/EngineAdmission.js.map +1 -0
- package/dist/esm/src/GASP/OverlayGASPRemote.js +27 -43
- package/dist/esm/src/GASP/OverlayGASPRemote.js.map +1 -1
- package/dist/esm/src/GASP/OverlayGASPStorage.js +200 -56
- package/dist/esm/src/GASP/OverlayGASPStorage.js.map +1 -1
- package/dist/esm/src/RemoteSecurity.js +279 -0
- package/dist/esm/src/RemoteSecurity.js.map +1 -0
- package/dist/esm/src/storage/AdmissionStorage.js +85 -0
- package/dist/esm/src/storage/AdmissionStorage.js.map +1 -0
- package/dist/esm/src/storage/RecoveryContract.js +31 -0
- package/dist/esm/src/storage/RecoveryContract.js.map +1 -0
- package/dist/esm/src/storage/Storage.js +4 -1
- package/dist/esm/src/storage/Storage.js.map +1 -1
- package/dist/esm/src/storage/knex/KnexStorage.js +98 -61
- package/dist/esm/src/storage/knex/KnexStorage.js.map +1 -1
- package/dist/esm/src/storage/knex/all-migrations.js +5 -1
- package/dist/esm/src/storage/knex/all-migrations.js.map +1 -1
- package/dist/esm/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.js +32 -0
- package/dist/esm/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.js.map +1 -0
- package/dist/esm/src/storage/knex/migrations/2026-09-20-001-spent-by.js +12 -0
- package/dist/esm/src/storage/knex/migrations/2026-09-20-001-spent-by.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoAdmissionPlan.js +217 -0
- package/dist/esm/src/storage/mongo/MongoAdmissionPlan.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoAdmissionStorage.js +673 -0
- package/dist/esm/src/storage/mongo/MongoAdmissionStorage.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoOverlayStorage.js +451 -0
- package/dist/esm/src/storage/mongo/MongoOverlayStorage.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoPayloadStore.js +747 -0
- package/dist/esm/src/storage/mongo/MongoPayloadStore.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoReadGuards.js +129 -0
- package/dist/esm/src/storage/mongo/MongoReadGuards.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoSchema.js +730 -0
- package/dist/esm/src/storage/mongo/MongoSchema.js.map +1 -0
- package/dist/esm/src/storage/mongo/MongoTransactionRunner.js +371 -0
- package/dist/esm/src/storage/mongo/MongoTransactionRunner.js.map +1 -0
- package/dist/esm/src/storage/mongo.js +9 -0
- package/dist/esm/src/storage/mongo.js.map +1 -0
- package/dist/types/mod.d.ts +3 -0
- package/dist/types/mod.d.ts.map +1 -1
- package/dist/types/src/BASM.d.ts +6 -0
- package/dist/types/src/BASM.d.ts.map +1 -1
- package/dist/types/src/BASMRemote.d.ts +8 -1
- package/dist/types/src/BASMRemote.d.ts.map +1 -1
- package/dist/types/src/BASMValidation.d.ts +27 -0
- package/dist/types/src/BASMValidation.d.ts.map +1 -0
- package/dist/types/src/DiscoveryAdvertisementValidation.d.ts +11 -0
- package/dist/types/src/DiscoveryAdvertisementValidation.d.ts.map +1 -0
- package/dist/types/src/Engine.d.ts +37 -13
- package/dist/types/src/Engine.d.ts.map +1 -1
- package/dist/types/src/EngineAdmission.d.ts +70 -0
- package/dist/types/src/EngineAdmission.d.ts.map +1 -0
- package/dist/types/src/GASP/OverlayGASPRemote.d.ts +4 -3
- package/dist/types/src/GASP/OverlayGASPRemote.d.ts.map +1 -1
- package/dist/types/src/GASP/OverlayGASPStorage.d.ts +22 -16
- package/dist/types/src/GASP/OverlayGASPStorage.d.ts.map +1 -1
- package/dist/types/src/RemoteSecurity.d.ts +50 -0
- package/dist/types/src/RemoteSecurity.d.ts.map +1 -0
- package/dist/types/src/storage/AdmissionStorage.d.ts +185 -0
- package/dist/types/src/storage/AdmissionStorage.d.ts.map +1 -0
- package/dist/types/src/storage/RecoveryContract.d.ts +50 -0
- package/dist/types/src/storage/RecoveryContract.d.ts.map +1 -0
- package/dist/types/src/storage/Storage.d.ts +32 -19
- package/dist/types/src/storage/Storage.d.ts.map +1 -1
- package/dist/types/src/storage/knex/KnexStorage.d.ts +8 -8
- package/dist/types/src/storage/knex/KnexStorage.d.ts.map +1 -1
- package/dist/types/src/storage/knex/all-migrations.d.ts.map +1 -1
- package/dist/types/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.d.ts +4 -0
- package/dist/types/src/storage/knex/migrations/2026-09-17-001-topical-uniqueness.d.ts.map +1 -0
- package/dist/types/src/storage/knex/migrations/2026-09-20-001-spent-by.d.ts +5 -0
- package/dist/types/src/storage/knex/migrations/2026-09-20-001-spent-by.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoAdmissionPlan.d.ts +18 -0
- package/dist/types/src/storage/mongo/MongoAdmissionPlan.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoAdmissionStorage.d.ts +112 -0
- package/dist/types/src/storage/mongo/MongoAdmissionStorage.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoOverlayStorage.d.ts +71 -0
- package/dist/types/src/storage/mongo/MongoOverlayStorage.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoPayloadStore.d.ts +134 -0
- package/dist/types/src/storage/mongo/MongoPayloadStore.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoReadGuards.d.ts +44 -0
- package/dist/types/src/storage/mongo/MongoReadGuards.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoSchema.d.ts +67 -0
- package/dist/types/src/storage/mongo/MongoSchema.d.ts.map +1 -0
- package/dist/types/src/storage/mongo/MongoTransactionRunner.d.ts +69 -0
- package/dist/types/src/storage/mongo/MongoTransactionRunner.d.ts.map +1 -0
- package/dist/types/src/storage/mongo.d.ts +9 -0
- package/dist/types/src/storage/mongo.d.ts.map +1 -0
- package/package.json +11 -5
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REMOTE_BODY_TIMEOUT_MS = exports.MAX_RAW_TRANSACTION_BYTES = exports.MAX_GASP_NODE_JSON_BYTES = exports.MAX_REMOTE_JSON_BYTES = exports.MAX_BASM_TXIDS = exports.MAX_GASP_PAGE_SIZE = void 0;
|
|
4
|
+
exports.validateAdmittanceInstructions = validateAdmittanceInstructions;
|
|
5
|
+
exports.assertTopic = assertTopic;
|
|
6
|
+
exports.assertRegistryName = assertRegistryName;
|
|
7
|
+
exports.assertHash = assertHash;
|
|
8
|
+
exports.assertOutputIndex = assertOutputIndex;
|
|
9
|
+
exports.assertNonnegativeInteger = assertNonnegativeInteger;
|
|
10
|
+
exports.assertOutpoint = assertOutpoint;
|
|
11
|
+
exports.assertHexBytes = assertHexBytes;
|
|
12
|
+
exports.assertTxidList = assertTxidList;
|
|
13
|
+
exports.normalizePeerEndpoint = normalizePeerEndpoint;
|
|
14
|
+
exports.securePeerFetch = securePeerFetch;
|
|
15
|
+
exports.readPeerJSON = readPeerJSON;
|
|
16
|
+
exports.assertGASPInitialResponse = assertGASPInitialResponse;
|
|
17
|
+
exports.assertGASPNode = assertGASPNode;
|
|
18
|
+
exports.assertRawTransactionMatches = assertRawTransactionMatches;
|
|
19
|
+
const sdk_1 = require("@bsv/sdk");
|
|
20
|
+
exports.MAX_GASP_PAGE_SIZE = 10000;
|
|
21
|
+
exports.MAX_BASM_TXIDS = 256;
|
|
22
|
+
exports.MAX_REMOTE_JSON_BYTES = 64 * 1024 * 1024;
|
|
23
|
+
exports.MAX_GASP_NODE_JSON_BYTES = 32 * 1024 * 1024;
|
|
24
|
+
exports.MAX_RAW_TRANSACTION_BYTES = 32 * 1024 * 1024;
|
|
25
|
+
exports.REMOTE_BODY_TIMEOUT_MS = 30000;
|
|
26
|
+
const MAX_TOPIC_BYTES = 256;
|
|
27
|
+
const MAX_METADATA_BYTES = 1024 * 1024;
|
|
28
|
+
const MAX_GASP_INPUTS = 100000;
|
|
29
|
+
const MAX_ERROR_SNIPPET_BYTES = 1024;
|
|
30
|
+
const HASH_HEX = /^[0-9a-fA-F]{64}$/;
|
|
31
|
+
const EVEN_HEX = /^(?:[0-9a-fA-F]{2})+$/;
|
|
32
|
+
function isRecord(value) {
|
|
33
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function validateAdmittanceInstructions(value, tx, previousCoins) {
|
|
36
|
+
if (!isRecord(value) ||
|
|
37
|
+
!Array.isArray(value.outputsToAdmit) ||
|
|
38
|
+
!Array.isArray(value.coinsToRetain)) {
|
|
39
|
+
throw new TypeError('Topic manager returned invalid admittance instructions');
|
|
40
|
+
}
|
|
41
|
+
const validateIndexes = (indexes, limit, label) => {
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
return indexes.map(index => {
|
|
44
|
+
if (typeof index !== 'number' ||
|
|
45
|
+
!Number.isSafeInteger(index) ||
|
|
46
|
+
index < 0 ||
|
|
47
|
+
index >= limit ||
|
|
48
|
+
seen.has(index)) {
|
|
49
|
+
throw new TypeError(`Topic manager returned invalid ${label}`);
|
|
50
|
+
}
|
|
51
|
+
seen.add(index);
|
|
52
|
+
return index;
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
const outputsToAdmit = validateIndexes(value.outputsToAdmit, tx.outputs.length, 'outputsToAdmit');
|
|
56
|
+
const coinsToRetain = validateIndexes(value.coinsToRetain, tx.inputs.length, 'coinsToRetain');
|
|
57
|
+
const previousCoinSet = new Set(previousCoins);
|
|
58
|
+
if (coinsToRetain.some(index => !previousCoinSet.has(index))) {
|
|
59
|
+
throw new TypeError('Topic manager retained an input that is not a previous topical coin');
|
|
60
|
+
}
|
|
61
|
+
return { outputsToAdmit, coinsToRetain };
|
|
62
|
+
}
|
|
63
|
+
function assertTopic(topic, label = 'topic') {
|
|
64
|
+
if (typeof topic !== 'string' ||
|
|
65
|
+
topic.length === 0 ||
|
|
66
|
+
new TextEncoder().encode(topic).byteLength > MAX_TOPIC_BYTES ||
|
|
67
|
+
Array.from(topic).some(character => {
|
|
68
|
+
var _a;
|
|
69
|
+
const codePoint = (_a = character.codePointAt(0)) !== null && _a !== void 0 ? _a : 0;
|
|
70
|
+
return codePoint <= 0x1f || codePoint === 0x7f;
|
|
71
|
+
})) {
|
|
72
|
+
throw new TypeError(`${label} is invalid`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function assertRegistryName(value, label) {
|
|
76
|
+
assertTopic(value, label);
|
|
77
|
+
if (value === '__proto__' || value === 'prototype' || value === 'constructor') {
|
|
78
|
+
throw new TypeError(`${label} uses a reserved object property name`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function assertHash(value, label) {
|
|
82
|
+
if (typeof value !== 'string' || !HASH_HEX.test(value)) {
|
|
83
|
+
throw new TypeError(`${label} must be 32 bytes of hex`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function assertOutputIndex(value, label) {
|
|
87
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 0xffffffff) {
|
|
88
|
+
throw new TypeError(`${label} must be an unsigned 32-bit integer`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function assertNonnegativeInteger(value, label) {
|
|
92
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
93
|
+
throw new TypeError(`${label} must be a non-negative safe integer`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function assertOutpoint(value, label) {
|
|
97
|
+
if (typeof value !== 'string')
|
|
98
|
+
throw new TypeError(`${label} is invalid`);
|
|
99
|
+
const separator = value.lastIndexOf('.');
|
|
100
|
+
if (separator !== 64)
|
|
101
|
+
throw new TypeError(`${label} is invalid`);
|
|
102
|
+
assertHash(value.slice(0, separator), `${label} txid`);
|
|
103
|
+
const index = value.slice(separator + 1);
|
|
104
|
+
if (!/^(0|[1-9]\d*)$/.test(index))
|
|
105
|
+
throw new TypeError(`${label} is invalid`);
|
|
106
|
+
assertOutputIndex(Number(index), `${label} output index`);
|
|
107
|
+
}
|
|
108
|
+
function assertHexBytes(value, label, maxBytes, allowEmpty = false) {
|
|
109
|
+
if (typeof value !== 'string' ||
|
|
110
|
+
(!allowEmpty && value.length === 0) ||
|
|
111
|
+
value.length > maxBytes * 2 ||
|
|
112
|
+
(value.length !== 0 && !EVEN_HEX.test(value))) {
|
|
113
|
+
throw new TypeError(`${label} must be bounded, even-length hexadecimal data`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function assertTxidList(value, label, options = {}) {
|
|
117
|
+
var _a;
|
|
118
|
+
const max = (_a = options.max) !== null && _a !== void 0 ? _a : exports.MAX_BASM_TXIDS;
|
|
119
|
+
if (!Array.isArray(value) || (!options.allowEmpty && value.length === 0) || value.length > max) {
|
|
120
|
+
throw new TypeError(`${label} must contain between ${options.allowEmpty === true ? 0 : 1} and ${max} txids`);
|
|
121
|
+
}
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
for (const [index, txid] of value.entries()) {
|
|
124
|
+
assertHash(txid, `${label}[${index}]`);
|
|
125
|
+
const canonical = txid.toLowerCase();
|
|
126
|
+
if (seen.has(canonical))
|
|
127
|
+
throw new TypeError(`${label} contains duplicate txids`);
|
|
128
|
+
seen.add(canonical);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function normalizePeerEndpoint(endpoint) {
|
|
132
|
+
const url = new URL(endpoint);
|
|
133
|
+
if (url.protocol !== 'https:' ||
|
|
134
|
+
url.username !== '' ||
|
|
135
|
+
url.password !== '' ||
|
|
136
|
+
url.hash !== '' ||
|
|
137
|
+
url.search !== '') {
|
|
138
|
+
throw new TypeError('Overlay peer endpoints must be credential-free HTTPS URLs without query or fragment data');
|
|
139
|
+
}
|
|
140
|
+
return url.toString().replace(/\/$/, '');
|
|
141
|
+
}
|
|
142
|
+
function securePeerFetch(endpoint, supplied) {
|
|
143
|
+
const normalized = normalizePeerEndpoint(endpoint);
|
|
144
|
+
return {
|
|
145
|
+
endpoint: normalized,
|
|
146
|
+
fetchImpl: supplied !== null && supplied !== void 0 ? supplied : (0, sdk_1.createPublicHTTPSFetch)(new URL(normalized).origin)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function readBody(response, maxBytes, truncate = false) {
|
|
150
|
+
var _a, _b, _c;
|
|
151
|
+
const declared = (_b = (_a = response.headers) === null || _a === void 0 ? void 0 : _a.get) === null || _b === void 0 ? void 0 : _b.call(_a, 'content-length');
|
|
152
|
+
if (declared !== null && declared !== undefined) {
|
|
153
|
+
if (!truncate && (!/^(0|[1-9]\d*)$/.test(declared) || Number(declared) > maxBytes)) {
|
|
154
|
+
await ((_c = response.body) === null || _c === void 0 ? void 0 : _c.cancel());
|
|
155
|
+
throw new RangeError(`Overlay peer response exceeds ${maxBytes} bytes`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (response.body === null || response.body === undefined) {
|
|
159
|
+
const text = await response.text();
|
|
160
|
+
if (new TextEncoder().encode(text).byteLength > maxBytes) {
|
|
161
|
+
throw new RangeError(`Overlay peer response exceeds ${maxBytes} bytes`);
|
|
162
|
+
}
|
|
163
|
+
return text;
|
|
164
|
+
}
|
|
165
|
+
const reader = response.body.getReader();
|
|
166
|
+
const chunks = [];
|
|
167
|
+
let total = 0;
|
|
168
|
+
let timeout;
|
|
169
|
+
try {
|
|
170
|
+
const bytes = await Promise.race([
|
|
171
|
+
(async () => {
|
|
172
|
+
while (true) {
|
|
173
|
+
const { done, value } = await reader.read();
|
|
174
|
+
if (done)
|
|
175
|
+
break;
|
|
176
|
+
if (truncate && total + value.byteLength > maxBytes) {
|
|
177
|
+
chunks.push(value.slice(0, maxBytes - total));
|
|
178
|
+
total = maxBytes;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
total += value.byteLength;
|
|
182
|
+
if (total > maxBytes) {
|
|
183
|
+
throw new RangeError(`Overlay peer response exceeds ${maxBytes} bytes`);
|
|
184
|
+
}
|
|
185
|
+
chunks.push(value);
|
|
186
|
+
}
|
|
187
|
+
const combined = new Uint8Array(total);
|
|
188
|
+
let offset = 0;
|
|
189
|
+
for (const chunk of chunks) {
|
|
190
|
+
combined.set(chunk, offset);
|
|
191
|
+
offset += chunk.byteLength;
|
|
192
|
+
}
|
|
193
|
+
return combined;
|
|
194
|
+
})(),
|
|
195
|
+
new Promise((_resolve, reject) => {
|
|
196
|
+
timeout = setTimeout(() => reject(new Error('Overlay peer response body timed out')), exports.REMOTE_BODY_TIMEOUT_MS);
|
|
197
|
+
})
|
|
198
|
+
]);
|
|
199
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
if (timeout !== undefined)
|
|
203
|
+
clearTimeout(timeout);
|
|
204
|
+
await reader.cancel().catch(() => { });
|
|
205
|
+
reader.releaseLock();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async function readPeerJSON(response, maxBytes = exports.MAX_REMOTE_JSON_BYTES) {
|
|
209
|
+
var _a, _b, _c;
|
|
210
|
+
const contentType = (_b = (_a = response.headers) === null || _a === void 0 ? void 0 : _a.get) === null || _b === void 0 ? void 0 : _b.call(_a, 'content-type');
|
|
211
|
+
if (contentType !== null &&
|
|
212
|
+
contentType !== undefined &&
|
|
213
|
+
!/^application\/(?:[\w.-]+\+)?json(?:\s*;|$)/i.test(contentType)) {
|
|
214
|
+
await ((_c = response.body) === null || _c === void 0 ? void 0 : _c.cancel());
|
|
215
|
+
throw new TypeError('Overlay peer response is not JSON');
|
|
216
|
+
}
|
|
217
|
+
const text = await readBody(response, response.ok ? maxBytes : Math.min(maxBytes, MAX_ERROR_SNIPPET_BYTES), !response.ok);
|
|
218
|
+
if (!response.ok) {
|
|
219
|
+
const snippet = new TextDecoder().decode(new TextEncoder().encode(text).slice(0, MAX_ERROR_SNIPPET_BYTES));
|
|
220
|
+
throw new Error(`Overlay peer returned HTTP ${response.status}: ${JSON.stringify(snippet)}`);
|
|
221
|
+
}
|
|
222
|
+
if (text.length === 0)
|
|
223
|
+
throw new TypeError('Overlay peer returned an empty JSON response');
|
|
224
|
+
try {
|
|
225
|
+
return JSON.parse(text);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
throw new TypeError('Overlay peer returned malformed JSON');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function assertGASPInitialResponse(value, maxOutputs) {
|
|
232
|
+
if (!isRecord(value) || !Array.isArray(value.UTXOList) || value.UTXOList.length > maxOutputs) {
|
|
233
|
+
throw new TypeError('Invalid GASP initial response');
|
|
234
|
+
}
|
|
235
|
+
assertNonnegativeInteger(value.since, 'GASP response since');
|
|
236
|
+
const seen = new Set();
|
|
237
|
+
for (const [index, item] of value.UTXOList.entries()) {
|
|
238
|
+
if (!isRecord(item))
|
|
239
|
+
throw new TypeError(`GASP UTXOList[${index}] is invalid`);
|
|
240
|
+
assertHash(item.txid, `GASP UTXOList[${index}].txid`);
|
|
241
|
+
assertOutputIndex(item.outputIndex, `GASP UTXOList[${index}].outputIndex`);
|
|
242
|
+
assertNonnegativeInteger(item.score, `GASP UTXOList[${index}].score`);
|
|
243
|
+
const outpoint = `${item.txid.toLowerCase()}.${item.outputIndex}`;
|
|
244
|
+
if (seen.has(outpoint))
|
|
245
|
+
throw new TypeError('GASP initial response contains duplicate outpoints');
|
|
246
|
+
seen.add(outpoint);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function assertGASPNode(value, expected) {
|
|
250
|
+
if (!isRecord(value))
|
|
251
|
+
throw new TypeError('Invalid GASP node response');
|
|
252
|
+
assertOutpoint(value.graphID, 'GASP node graphID');
|
|
253
|
+
if (value.graphID !== expected.graphID)
|
|
254
|
+
throw new TypeError('GASP node graphID does not match the request');
|
|
255
|
+
assertOutputIndex(value.outputIndex, 'GASP node outputIndex');
|
|
256
|
+
if (value.outputIndex !== expected.outputIndex) {
|
|
257
|
+
throw new TypeError('GASP node outputIndex does not match the request');
|
|
258
|
+
}
|
|
259
|
+
assertHexBytes(value.rawTx, 'GASP node rawTx', exports.MAX_RAW_TRANSACTION_BYTES);
|
|
260
|
+
let actualTxid;
|
|
261
|
+
try {
|
|
262
|
+
actualTxid = sdk_1.Transaction.fromHex(value.rawTx).id('hex');
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
throw new TypeError('GASP node rawTx is not a valid transaction');
|
|
266
|
+
}
|
|
267
|
+
if (actualTxid.toLowerCase() !== expected.txid.toLowerCase()) {
|
|
268
|
+
throw new TypeError('GASP node transaction does not match the requested txid');
|
|
269
|
+
}
|
|
270
|
+
for (const field of ['proof', 'txMetadata', 'outputMetadata']) {
|
|
271
|
+
if (value[field] !== undefined) {
|
|
272
|
+
assertHexBytes(value[field], `GASP node ${field}`, field === 'proof' ? exports.MAX_RAW_TRANSACTION_BYTES : MAX_METADATA_BYTES, true);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (value.inputs !== undefined) {
|
|
276
|
+
if (!isRecord(value.inputs) || Object.keys(value.inputs).length > MAX_GASP_INPUTS) {
|
|
277
|
+
throw new TypeError('GASP node inputs are invalid');
|
|
278
|
+
}
|
|
279
|
+
for (const [outpoint, metadata] of Object.entries(value.inputs)) {
|
|
280
|
+
assertOutpoint(outpoint, 'GASP node input outpoint');
|
|
281
|
+
if (!isRecord(metadata))
|
|
282
|
+
throw new TypeError('GASP node input metadata is invalid');
|
|
283
|
+
assertHash(metadata.hash, 'GASP node input metadata hash');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function assertRawTransactionMatches(txid, rawTx) {
|
|
288
|
+
assertHash(txid, 'transaction txid');
|
|
289
|
+
assertHexBytes(rawTx, 'raw transaction', exports.MAX_RAW_TRANSACTION_BYTES);
|
|
290
|
+
let actual;
|
|
291
|
+
try {
|
|
292
|
+
actual = sdk_1.Transaction.fromHex(rawTx).id('hex');
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
throw new TypeError('Peer returned an invalid raw transaction');
|
|
296
|
+
}
|
|
297
|
+
if (actual.toLowerCase() !== txid.toLowerCase()) {
|
|
298
|
+
throw new TypeError('Peer raw transaction does not match its txid');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=RemoteSecurity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RemoteSecurity.js","sourceRoot":"","sources":["../../../src/RemoteSecurity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import type { HistoryRevisionHandoff } from './RecoveryContract.js';
|
|
2
|
+
/** Canonical unsigned decimal, 0..2^64-1. Never round through a JS number. */
|
|
3
|
+
export type StorageUint64 = string & {
|
|
4
|
+
readonly __brand: unique symbol;
|
|
5
|
+
};
|
|
6
|
+
export interface StorageScope {
|
|
7
|
+
network: string;
|
|
8
|
+
genesisHash: string;
|
|
9
|
+
nodeId: string;
|
|
10
|
+
}
|
|
11
|
+
/** These revisions are independent: a late admission need not be a reorg. */
|
|
12
|
+
export interface HistoryFence {
|
|
13
|
+
chainEpoch: StorageUint64;
|
|
14
|
+
topicHistoryGeneration: StorageUint64;
|
|
15
|
+
}
|
|
16
|
+
export interface AdmissionIdentity {
|
|
17
|
+
scope: StorageScope;
|
|
18
|
+
/** Derived from verified immutable transaction bytes before storage is called. */
|
|
19
|
+
txid: string;
|
|
20
|
+
mode: 'live' | 'historical';
|
|
21
|
+
/** Digest of off-chain values and any other immutable admission-policy inputs. */
|
|
22
|
+
contextDigest: string;
|
|
23
|
+
topics: Array<{
|
|
24
|
+
topic: string;
|
|
25
|
+
policyId: string;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export interface AdmissionOperationKey {
|
|
29
|
+
scope: StorageScope;
|
|
30
|
+
operationId: string;
|
|
31
|
+
semanticDigest: string;
|
|
32
|
+
}
|
|
33
|
+
/** Small reference to content published outside the database transaction. */
|
|
34
|
+
export interface AdmissionPayloadRef {
|
|
35
|
+
digest: string;
|
|
36
|
+
byteLength: StorageUint64;
|
|
37
|
+
kind: 'raw-transaction' | 'merkle-path' | 'beef-manifest' | 'locking-script' | 'outbox-data';
|
|
38
|
+
}
|
|
39
|
+
export interface AdmissionOutpoint {
|
|
40
|
+
txid: string;
|
|
41
|
+
/** Canonical decimal uint32, the transaction wire outpoint index domain. */
|
|
42
|
+
outputIndex: StorageUint64;
|
|
43
|
+
}
|
|
44
|
+
/** Adapter-issued revision token; absence is also a read predicate. */
|
|
45
|
+
export interface AdmissionReadPredicate {
|
|
46
|
+
key: string;
|
|
47
|
+
expectedVersion: string | null;
|
|
48
|
+
}
|
|
49
|
+
export interface AdmissionOutput extends AdmissionOutpoint {
|
|
50
|
+
satoshis: StorageUint64;
|
|
51
|
+
score: StorageUint64;
|
|
52
|
+
/** A byte range supports even an individually oversized output script. */
|
|
53
|
+
script: {
|
|
54
|
+
payload: AdmissionPayloadRef;
|
|
55
|
+
offset: StorageUint64;
|
|
56
|
+
byteLength: StorageUint64;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export interface AdmissionTopicDecision {
|
|
60
|
+
topic: string;
|
|
61
|
+
expectedHistory: HistoryFence;
|
|
62
|
+
/** Includes all point/range/projection reads that influenced topic admission. */
|
|
63
|
+
reads: AdmissionReadPredicate[];
|
|
64
|
+
spends: Array<{
|
|
65
|
+
outpoint: AdmissionOutpoint;
|
|
66
|
+
expectedVersion: string;
|
|
67
|
+
spender: string;
|
|
68
|
+
}>;
|
|
69
|
+
/** Remove current serving outputs only; retain applied history and evidence. */
|
|
70
|
+
evictions: AdmissionOutpoint[];
|
|
71
|
+
outputs: AdmissionOutput[];
|
|
72
|
+
edges: Array<{
|
|
73
|
+
source: AdmissionOutpoint;
|
|
74
|
+
consumer: AdmissionOutpoint;
|
|
75
|
+
}>;
|
|
76
|
+
/** Retain this history after output spend, serving moderation or index eviction. */
|
|
77
|
+
applied: {
|
|
78
|
+
txid: string;
|
|
79
|
+
firstSeenHeight?: StorageUint64;
|
|
80
|
+
proof?: AdmissionPayloadRef;
|
|
81
|
+
block?: {
|
|
82
|
+
height: StorageUint64;
|
|
83
|
+
hash: string;
|
|
84
|
+
index: StorageUint64;
|
|
85
|
+
merkleRoot: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
/** Invalidate downstream anchors/comparisons; own repair checkpoint moves atomically. */
|
|
89
|
+
historyUpdate?: {
|
|
90
|
+
nextTopicHistoryGeneration: StorageUint64;
|
|
91
|
+
affectedFromHeight: StorageUint64;
|
|
92
|
+
/** Present when a recovery worker itself caused this history revision. */
|
|
93
|
+
handoff?: HistoryRevisionHandoff;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Every event has a stable scope-local ID and ready payload references. */
|
|
97
|
+
export interface AdmissionOutboxIntent {
|
|
98
|
+
eventId: string;
|
|
99
|
+
kind: 'lookup' | 'propagation';
|
|
100
|
+
target: string;
|
|
101
|
+
payloads: AdmissionPayloadRef[];
|
|
102
|
+
}
|
|
103
|
+
export interface AdmissionCommit {
|
|
104
|
+
key: AdmissionOperationKey;
|
|
105
|
+
identity: AdmissionIdentity;
|
|
106
|
+
/** Shared raw/proof components or a manifest; never per-output inline BEEF. */
|
|
107
|
+
payloads: AdmissionPayloadRef[];
|
|
108
|
+
decisions: AdmissionTopicDecision[];
|
|
109
|
+
outbox: AdmissionOutboxIntent[];
|
|
110
|
+
/** Exact UTF-8 STEAK JSON saved with the commit, then replayed without regeneration. */
|
|
111
|
+
steak: string;
|
|
112
|
+
}
|
|
113
|
+
export interface AdmissionReceipt {
|
|
114
|
+
operationId: string;
|
|
115
|
+
semanticDigest: string;
|
|
116
|
+
/** Only the selected adapter can establish this guarantee. */
|
|
117
|
+
durability: 'atomic-local';
|
|
118
|
+
steak: string;
|
|
119
|
+
/** Only enlisted indexes may be visible at commit. External indexes remain pending. */
|
|
120
|
+
indexes: Array<{
|
|
121
|
+
target: string;
|
|
122
|
+
state: 'visible' | 'pending';
|
|
123
|
+
}>;
|
|
124
|
+
propagation: 'not-requested' | 'pending';
|
|
125
|
+
}
|
|
126
|
+
/** Pending is not an ACK. Unknown commit must retain its opaque attempt identity. */
|
|
127
|
+
export type AdmissionCommitResult = {
|
|
128
|
+
state: 'committed';
|
|
129
|
+
receipt: AdmissionReceipt;
|
|
130
|
+
} | {
|
|
131
|
+
state: 'pending';
|
|
132
|
+
attemptId: string;
|
|
133
|
+
} | {
|
|
134
|
+
state: 'rejected';
|
|
135
|
+
code: 'digest-mismatch' | 'read-conflict' | 'spend-conflict' | 'payload-not-ready' | 'unsupported-projection' | 'invalid-plan';
|
|
136
|
+
};
|
|
137
|
+
export type AdmissionReconcileResult = AdmissionCommitResult | {
|
|
138
|
+
state: 'aborted';
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Optional v1 contract, separate from legacy CRUD Storage. No current adapter or
|
|
142
|
+
* Engine call path implements it. A provider must atomically revalidate reads,
|
|
143
|
+
* fences, conditional spends and ready-payload pins, and save every effect plus
|
|
144
|
+
* the receipt. Matching retries return the saved receipt before checking stale
|
|
145
|
+
* reads; conflicting semantic digests reject. Do not run verification, uploads,
|
|
146
|
+
* network requests or arbitrary plug-ins inside commitAdmission.
|
|
147
|
+
*
|
|
148
|
+
* TransientTransactionError permits a fresh whole-body attempt after abort and
|
|
149
|
+
* reread/redecision. UnknownTransactionCommitResult requires reconcileAdmission
|
|
150
|
+
* on the SAME attempt until committed or definitively aborted; absence of an
|
|
151
|
+
* operation record alone does not establish abort. Repeated commitAdmission
|
|
152
|
+
* must first recover any persisted unresolved attempt for this operation, even
|
|
153
|
+
* after a lost response or process restart, before it can start a fresh body.
|
|
154
|
+
* Transport failures remain
|
|
155
|
+
* errors, never rejection/abort or a successful local ACK.
|
|
156
|
+
*/
|
|
157
|
+
export interface AdmissionStorage {
|
|
158
|
+
readonly protocol: 'overlay-admission-v1';
|
|
159
|
+
commitAdmission: (plan: AdmissionCommit) => Promise<AdmissionCommitResult>;
|
|
160
|
+
reconcileAdmission: (key: AdmissionOperationKey, attemptId?: string) => Promise<AdmissionReconcileResult>;
|
|
161
|
+
}
|
|
162
|
+
/** External projection delivery may be retried only with both capabilities. */
|
|
163
|
+
export interface ReplaySafeProjection {
|
|
164
|
+
readonly protocol: 'overlay-projection-v1';
|
|
165
|
+
applyEvent: (scope: StorageScope, intent: AdmissionOutboxIntent) => Promise<{
|
|
166
|
+
checkpoint: string;
|
|
167
|
+
}>;
|
|
168
|
+
reconcile: (scope: StorageScope, checkpoint: string | null) => Promise<{
|
|
169
|
+
checkpoint: string;
|
|
170
|
+
}>;
|
|
171
|
+
}
|
|
172
|
+
/** Shape detection is a declaration, not proof that an adapter is durable. */
|
|
173
|
+
export declare function getAdmissionStorage(storage: unknown): AdmissionStorage | undefined;
|
|
174
|
+
export declare function isReplaySafeProjection(projection: unknown): projection is ReplaySafeProjection;
|
|
175
|
+
export declare function parseStorageUint64(value: string): bigint;
|
|
176
|
+
export declare function asStorageUint64(value: string): StorageUint64;
|
|
177
|
+
/** Validate the wire outpoint domain before conversion to an exact STEAK number. */
|
|
178
|
+
export declare function parseStorageOutputIndex(value: string): number;
|
|
179
|
+
/**
|
|
180
|
+
* SHA-256 of UTF-8 length-framed fields, see specs/overlay/persistence-v1.md.
|
|
181
|
+
* Mutable reads/decisions and proof variants are deliberately outside semantic
|
|
182
|
+
* identity. Their validation and atomic read predicates remain mandatory.
|
|
183
|
+
*/
|
|
184
|
+
export declare function admissionSemanticDigest(identity: AdmissionIdentity): string;
|
|
185
|
+
//# sourceMappingURL=AdmissionStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdmissionStorage.d.ts","sourceRoot":"","sources":["../../../../src/storage/AdmissionStorage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAdmissionStorage = getAdmissionStorage;
|
|
4
|
+
exports.isReplaySafeProjection = isReplaySafeProjection;
|
|
5
|
+
exports.parseStorageUint64 = parseStorageUint64;
|
|
6
|
+
exports.asStorageUint64 = asStorageUint64;
|
|
7
|
+
exports.parseStorageOutputIndex = parseStorageOutputIndex;
|
|
8
|
+
exports.admissionSemanticDigest = admissionSemanticDigest;
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
|
+
/** Shape detection is a declaration, not proof that an adapter is durable. */
|
|
11
|
+
function getAdmissionStorage(storage) {
|
|
12
|
+
if (typeof storage !== 'object' || storage === null || !('admission' in storage))
|
|
13
|
+
return undefined;
|
|
14
|
+
const candidate = storage.admission;
|
|
15
|
+
if (typeof candidate !== 'object' || candidate === null)
|
|
16
|
+
return undefined;
|
|
17
|
+
if (!('protocol' in candidate) || candidate.protocol !== 'overlay-admission-v1')
|
|
18
|
+
return undefined;
|
|
19
|
+
if (!('commitAdmission' in candidate) || typeof candidate.commitAdmission !== 'function')
|
|
20
|
+
return undefined;
|
|
21
|
+
if (!('reconcileAdmission' in candidate) || typeof candidate.reconcileAdmission !== 'function')
|
|
22
|
+
return undefined;
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
function isReplaySafeProjection(projection) {
|
|
26
|
+
return (typeof projection === 'object' &&
|
|
27
|
+
projection !== null &&
|
|
28
|
+
'protocol' in projection &&
|
|
29
|
+
projection.protocol === 'overlay-projection-v1' &&
|
|
30
|
+
'applyEvent' in projection &&
|
|
31
|
+
typeof projection.applyEvent === 'function' &&
|
|
32
|
+
'reconcile' in projection &&
|
|
33
|
+
typeof projection.reconcile === 'function');
|
|
34
|
+
}
|
|
35
|
+
function parseStorageUint64(value) {
|
|
36
|
+
if (typeof value !== 'string' || !/^(0|[1-9]\d{0,19})$/.test(value))
|
|
37
|
+
throw new Error('Invalid storage uint64');
|
|
38
|
+
const result = BigInt(value);
|
|
39
|
+
if (result > BigInt('18446744073709551615'))
|
|
40
|
+
throw new Error('Invalid storage uint64');
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
function asStorageUint64(value) {
|
|
44
|
+
parseStorageUint64(value);
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
/** Validate the wire outpoint domain before conversion to an exact STEAK number. */
|
|
48
|
+
function parseStorageOutputIndex(value) {
|
|
49
|
+
const result = parseStorageUint64(value);
|
|
50
|
+
if (result > BigInt('4294967295'))
|
|
51
|
+
throw new Error('Invalid storage output index');
|
|
52
|
+
return Number(result);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* SHA-256 of UTF-8 length-framed fields, see specs/overlay/persistence-v1.md.
|
|
56
|
+
* Mutable reads/decisions and proof variants are deliberately outside semantic
|
|
57
|
+
* identity. Their validation and atomic read predicates remain mandatory.
|
|
58
|
+
*/
|
|
59
|
+
function admissionSemanticDigest(identity) {
|
|
60
|
+
if (!/^[0-9a-f]{64}$/.test(identity.txid) ||
|
|
61
|
+
!/^[0-9a-f]{64}$/.test(identity.scope.genesisHash) ||
|
|
62
|
+
!/^[0-9a-f]{64}$/.test(identity.contextDigest)) {
|
|
63
|
+
throw new Error('Invalid admission hash');
|
|
64
|
+
}
|
|
65
|
+
if (identity.mode !== 'live' && identity.mode !== 'historical')
|
|
66
|
+
throw new Error('Invalid admission mode');
|
|
67
|
+
const topics = [...identity.topics].sort((a, b) => Buffer.compare(Buffer.from(a.topic), Buffer.from(b.topic)));
|
|
68
|
+
if (topics.length === 0 ||
|
|
69
|
+
topics.some((item, index) => index > 0 && item.topic === topics[index - 1].topic)) {
|
|
70
|
+
throw new Error('Invalid admission topics');
|
|
71
|
+
}
|
|
72
|
+
const fields = [
|
|
73
|
+
'overlay-admission-v1',
|
|
74
|
+
identity.scope.network,
|
|
75
|
+
identity.scope.genesisHash,
|
|
76
|
+
identity.scope.nodeId,
|
|
77
|
+
identity.txid,
|
|
78
|
+
identity.mode,
|
|
79
|
+
identity.contextDigest,
|
|
80
|
+
String(topics.length),
|
|
81
|
+
...topics.flatMap(({ topic, policyId }) => [topic, policyId])
|
|
82
|
+
];
|
|
83
|
+
const hash = (0, node_crypto_1.createHash)('sha256');
|
|
84
|
+
for (const field of fields) {
|
|
85
|
+
if (field.length === 0 || !field.isWellFormed())
|
|
86
|
+
throw new Error('Invalid admission identity');
|
|
87
|
+
const bytes = Buffer.from(field, 'utf8');
|
|
88
|
+
hash.update(String(bytes.length) + ':');
|
|
89
|
+
hash.update(bytes);
|
|
90
|
+
}
|
|
91
|
+
return hash.digest('hex');
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=AdmissionStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdmissionStorage.js","sourceRoot":"","sources":["../../../../src/storage/AdmissionStorage.ts"],"names":[],"mappings":"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"}
|