@totemsdk/wots-lease 1.0.0 → 1.0.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.
- package/LICENSE +202 -21
- package/NOTICE +60 -0
- package/dist/axia.d.ts +1 -1
- package/dist/axia.js +41 -28
- package/dist/certificate.d.ts +37 -0
- package/dist/certificate.js +69 -0
- package/dist/cjs/axia.d.ts +33 -0
- package/dist/cjs/axia.js +145 -0
- package/dist/cjs/certificate.d.ts +37 -0
- package/dist/cjs/certificate.js +74 -0
- package/dist/cjs/device.d.ts +18 -0
- package/dist/cjs/device.js +34 -0
- package/dist/cjs/errors.d.ts +71 -0
- package/dist/cjs/errors.js +135 -0
- package/dist/cjs/hybrid.d.ts +37 -0
- package/dist/cjs/hybrid.js +145 -0
- package/dist/cjs/index.d.ts +17 -0
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/journal.d.ts +30 -0
- package/dist/cjs/journal.js +369 -0
- package/dist/cjs/local.d.ts +83 -0
- package/dist/cjs/local.js +440 -0
- package/dist/cjs/onchain.d.ts +54 -0
- package/dist/cjs/onchain.js +314 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/quorum.d.ts +75 -0
- package/dist/cjs/quorum.js +307 -0
- package/dist/cjs/replicated-backup.d.ts +30 -0
- package/dist/cjs/replicated-backup.js +52 -0
- package/dist/cjs/seed.d.ts +41 -0
- package/dist/cjs/seed.js +84 -0
- package/dist/cjs/stubs.d.ts +50 -0
- package/dist/cjs/stubs.js +125 -0
- package/dist/cjs/types.d.ts +272 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/watermark.d.ts +51 -0
- package/dist/cjs/watermark.js +328 -0
- package/dist/device.js +2 -6
- package/dist/errors.d.ts +26 -0
- package/dist/errors.js +49 -25
- package/dist/hybrid.d.ts +4 -1
- package/dist/hybrid.js +72 -26
- package/dist/index.d.ts +6 -2
- package/dist/index.js +12 -38
- package/dist/journal.d.ts +14 -4
- package/dist/journal.js +327 -49
- package/dist/local.d.ts +31 -1
- package/dist/local.js +267 -68
- package/dist/onchain.d.ts +3 -1
- package/dist/onchain.js +63 -28
- package/dist/quorum.d.ts +15 -0
- package/dist/quorum.js +54 -15
- package/dist/replicated-backup.d.ts +30 -0
- package/dist/replicated-backup.js +48 -0
- package/dist/seed.d.ts +41 -0
- package/dist/seed.js +80 -0
- package/dist/stubs.d.ts +2 -0
- package/dist/stubs.js +20 -10
- package/dist/types.d.ts +74 -1
- package/dist/types.js +1 -2
- package/dist/watermark.d.ts +22 -1
- package/dist/watermark.js +133 -16
- package/package.json +25 -15
- package/rust/pkg/package.json +3 -3
- package/rust/pkg/wots_lease_wasm_bg.wasm +0 -0
- package/rust/pkg-node/package.json +3 -3
- package/rust/pkg-node/wots_lease_wasm_bg.wasm +0 -0
package/dist/hybrid.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* HybridLeaseProvider — recommended production default.
|
|
4
3
|
*
|
|
5
4
|
* Always uses local first, then gates on node cert and/or quorum attestation
|
|
6
5
|
* for transactions above a configurable value threshold.
|
|
7
6
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class HybridLeaseProvider {
|
|
7
|
+
import { signCertificate, certificateSignatureVerified } from './certificate.js';
|
|
8
|
+
export class HybridLeaseProvider {
|
|
11
9
|
constructor(config) {
|
|
12
10
|
this.local = config.local;
|
|
13
11
|
this.node = config.node;
|
|
14
12
|
this.quorum = config.quorum;
|
|
15
13
|
this.onchain = config.onchain;
|
|
16
14
|
this.threshold = config.threshold ?? Infinity;
|
|
15
|
+
this.certificateSigner = config.certificateSigner;
|
|
17
16
|
}
|
|
18
17
|
isHighValue(params) {
|
|
19
18
|
if (!params.valueHint)
|
|
@@ -22,29 +21,41 @@ class HybridLeaseProvider {
|
|
|
22
21
|
return !isNaN(val) && val >= this.threshold;
|
|
23
22
|
}
|
|
24
23
|
async reserveKeyUse(params) {
|
|
24
|
+
// Cross-instance/restore safety (RFC-013 §8/§9): before a high-value
|
|
25
|
+
// reservation, anchor the local cursor to the on-chain watermark so a second
|
|
26
|
+
// instance of the same seed cannot be handed a leaf we already used.
|
|
27
|
+
if (this.isHighValue(params) && this.onchain) {
|
|
28
|
+
try {
|
|
29
|
+
await this.onchain.syncLeaseJournal();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Chain unreachable — local monotonic watermark still guards reuse.
|
|
33
|
+
}
|
|
34
|
+
}
|
|
25
35
|
const reservation = await this.local.reserveKeyUse(params);
|
|
26
36
|
if (this.isHighValue(params)) {
|
|
27
37
|
// Layer 4 — quorum attestation over the SAME local slot.
|
|
28
38
|
if (this.quorum) {
|
|
29
39
|
try {
|
|
30
40
|
const attestations = await this.quorum.attestKeyUse(params, reservation.indices);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
signature: '',
|
|
45
|
-
attestations,
|
|
46
|
-
},
|
|
41
|
+
const certificate = {
|
|
42
|
+
reservationId: reservation.reservationId,
|
|
43
|
+
treeId: params.treeId,
|
|
44
|
+
branchId: params.branchId,
|
|
45
|
+
deviceId: params.deviceId,
|
|
46
|
+
indices: reservation.indices,
|
|
47
|
+
purpose: params.purpose,
|
|
48
|
+
payloadHash: params.payloadHash,
|
|
49
|
+
issuedBy: this.certificateSigner?.name ?? 'p2p-quorum',
|
|
50
|
+
issuedAt: Date.now(),
|
|
51
|
+
expiresAt: reservation.expiresAt,
|
|
52
|
+
signature: '',
|
|
53
|
+
attestations,
|
|
47
54
|
};
|
|
55
|
+
certificate.signature = this.certificateSigner
|
|
56
|
+
? await signCertificate(this.certificateSigner, certificate)
|
|
57
|
+
: '';
|
|
58
|
+
return { ...reservation, certificate };
|
|
48
59
|
}
|
|
49
60
|
catch {
|
|
50
61
|
// Quorum unavailable — fall through to node / local only.
|
|
@@ -72,24 +83,59 @@ class HybridLeaseProvider {
|
|
|
72
83
|
getLocalWatermark(treeId) {
|
|
73
84
|
return this.local.getLocalWatermark(treeId);
|
|
74
85
|
}
|
|
75
|
-
publishWatermark(treeId) {
|
|
86
|
+
async publishWatermark(treeId) {
|
|
87
|
+
// Anchor to the chain first (authoritative cross-instance cursor), then the
|
|
88
|
+
// personal node, then the local no-op.
|
|
89
|
+
if (this.onchain) {
|
|
90
|
+
try {
|
|
91
|
+
await this.onchain.publishWatermark(treeId);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// fall through
|
|
96
|
+
}
|
|
97
|
+
}
|
|
76
98
|
if (this.node) {
|
|
77
|
-
|
|
99
|
+
try {
|
|
100
|
+
await this.node.publishWatermark(treeId);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// fall through
|
|
105
|
+
}
|
|
78
106
|
}
|
|
79
|
-
|
|
107
|
+
await this.local.publishWatermark(treeId);
|
|
80
108
|
}
|
|
81
|
-
syncLeaseJournal() {
|
|
109
|
+
async syncLeaseJournal() {
|
|
110
|
+
// Read the authoritative on-chain cursor first so a restore/second instance
|
|
111
|
+
// advances past every leaf published by anyone holding this seed.
|
|
112
|
+
if (this.onchain) {
|
|
113
|
+
try {
|
|
114
|
+
return await this.onchain.syncLeaseJournal();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// fall through
|
|
118
|
+
}
|
|
119
|
+
}
|
|
82
120
|
if (this.node) {
|
|
83
|
-
|
|
121
|
+
try {
|
|
122
|
+
return await this.node.syncLeaseJournal();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// fall through
|
|
126
|
+
}
|
|
84
127
|
}
|
|
85
128
|
return this.local.syncLeaseJournal();
|
|
86
129
|
}
|
|
87
130
|
async verifyLeaseCertificate(cert) {
|
|
88
131
|
if (!cert)
|
|
89
132
|
return this.local.verifyLeaseCertificate(cert);
|
|
133
|
+
// Locally-assembled quorum certificates authenticate against our issuer.
|
|
134
|
+
if (cert.issuedBy === (this.certificateSigner?.name ?? 'p2p-quorum')) {
|
|
135
|
+
return certificateSignatureVerified(cert, this.certificateSigner);
|
|
136
|
+
}
|
|
90
137
|
if (this.node)
|
|
91
138
|
return this.node.verifyLeaseCertificate(cert);
|
|
92
139
|
return false;
|
|
93
140
|
}
|
|
94
141
|
}
|
|
95
|
-
exports.HybridLeaseProvider = HybridLeaseProvider;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export type { UnavailableReason, SigningIndices, LeaseStatus, TreeWatermark, WotsWatermarkState, LeaseCertificate, LeaseReservation, ReserveParams, LocalWatermark, ConflictRecord, SyncResult, WotsLeaseProvider, JournalEntry, DeviceKeyRange, PersonalLeaseNodeConfig, QuorumAttestation, QuorumPeer, P2PQuorumLeaseProviderConfig, OnchainWatermarkProviderConfig, } from './types.js';
|
|
1
|
+
export type { UnavailableReason, SigningIndices, LeaseStatus, TreeWatermark, WotsWatermarkState, LeaseCertificate, LeaseReservation, ReserveParams, LocalWatermark, WatermarkSeed, SeedWatermarkOptions, ConflictRecord, SyncResult, WotsLeaseProvider, JournalEntry, DeviceKeyRange, PersonalLeaseNodeConfig, QuorumAttestation, QuorumPeer, CertificateSigner, P2PQuorumLeaseProviderConfig, OnchainWatermarkProviderConfig, } from './types.js';
|
|
2
2
|
export { WotsWatermarkStore, flatIndex, fromFlatIndex, } from './watermark.js';
|
|
3
3
|
export { LeaseJournal } from './journal.js';
|
|
4
4
|
export { LocalLeaseProvider } from './local.js';
|
|
5
|
+
export { seedLeaseWatermark, exportLeaseWatermark } from './seed.js';
|
|
6
|
+
export type { SeedLeaseWatermarkParams } from './seed.js';
|
|
5
7
|
export { AxiaLeaseProvider } from './axia.js';
|
|
6
8
|
export type { AxiaLeaseProviderConfig } from './axia.js';
|
|
7
9
|
export { HybridLeaseProvider } from './hybrid.js';
|
|
@@ -10,4 +12,6 @@ export { PersonalLeaseNodeProvider, P2PQuorumLeaseProvider, OnchainWatermarkProv
|
|
|
10
12
|
export { P2PQuorumLeaseProvider as QuorumLeaseProvider } from './quorum.js';
|
|
11
13
|
export { OnchainWatermarkProvider as ChainWatermarkProvider } from './onchain.js';
|
|
12
14
|
export { allocateDeviceRange, deviceSlotForAddressIndex } from './device.js';
|
|
13
|
-
export { WatermarkMonotonicityError, WatermarkExhaustedError, LeaseNotFoundError, IndicesUnavailableError, PersonalLeaseNodeNotConfiguredError, P2PQuorumNotImplementedError, OnchainWatermarkNotImplementedError, QuorumUnavailableError, QuorumConflictError, OnchainWatermarkError, DeviceRangeViolationError, } from './errors.js';
|
|
15
|
+
export { WatermarkMonotonicityError, WatermarkExhaustedError, WatermarkSeedRegressionError, WatermarkSeedRequiredError, LeaseNotFoundError, IndicesUnavailableError, PersonalLeaseNodeNotConfiguredError, P2PQuorumNotImplementedError, OnchainWatermarkNotImplementedError, QuorumUnavailableError, QuorumConflictError, OnchainWatermarkError, DeviceRangeViolationError, } from './errors.js';
|
|
16
|
+
export { ReplicatedLeaseJournalBackup } from './replicated-backup.js';
|
|
17
|
+
export type { LeaseJournalRestoreTarget } from './replicated-backup.js';
|
package/dist/index.js
CHANGED
|
@@ -1,38 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(exports, "AxiaLeaseProvider", { enumerable: true, get: function () { return axia_js_1.AxiaLeaseProvider; } });
|
|
14
|
-
var hybrid_js_1 = require("./hybrid.js");
|
|
15
|
-
Object.defineProperty(exports, "HybridLeaseProvider", { enumerable: true, get: function () { return hybrid_js_1.HybridLeaseProvider; } });
|
|
16
|
-
var stubs_js_1 = require("./stubs.js");
|
|
17
|
-
Object.defineProperty(exports, "PersonalLeaseNodeProvider", { enumerable: true, get: function () { return stubs_js_1.PersonalLeaseNodeProvider; } });
|
|
18
|
-
Object.defineProperty(exports, "P2PQuorumLeaseProvider", { enumerable: true, get: function () { return stubs_js_1.P2PQuorumLeaseProvider; } });
|
|
19
|
-
Object.defineProperty(exports, "OnchainWatermarkProvider", { enumerable: true, get: function () { return stubs_js_1.OnchainWatermarkProvider; } });
|
|
20
|
-
var quorum_js_1 = require("./quorum.js");
|
|
21
|
-
Object.defineProperty(exports, "QuorumLeaseProvider", { enumerable: true, get: function () { return quorum_js_1.P2PQuorumLeaseProvider; } });
|
|
22
|
-
var onchain_js_1 = require("./onchain.js");
|
|
23
|
-
Object.defineProperty(exports, "ChainWatermarkProvider", { enumerable: true, get: function () { return onchain_js_1.OnchainWatermarkProvider; } });
|
|
24
|
-
var device_js_1 = require("./device.js");
|
|
25
|
-
Object.defineProperty(exports, "allocateDeviceRange", { enumerable: true, get: function () { return device_js_1.allocateDeviceRange; } });
|
|
26
|
-
Object.defineProperty(exports, "deviceSlotForAddressIndex", { enumerable: true, get: function () { return device_js_1.deviceSlotForAddressIndex; } });
|
|
27
|
-
var errors_js_1 = require("./errors.js");
|
|
28
|
-
Object.defineProperty(exports, "WatermarkMonotonicityError", { enumerable: true, get: function () { return errors_js_1.WatermarkMonotonicityError; } });
|
|
29
|
-
Object.defineProperty(exports, "WatermarkExhaustedError", { enumerable: true, get: function () { return errors_js_1.WatermarkExhaustedError; } });
|
|
30
|
-
Object.defineProperty(exports, "LeaseNotFoundError", { enumerable: true, get: function () { return errors_js_1.LeaseNotFoundError; } });
|
|
31
|
-
Object.defineProperty(exports, "IndicesUnavailableError", { enumerable: true, get: function () { return errors_js_1.IndicesUnavailableError; } });
|
|
32
|
-
Object.defineProperty(exports, "PersonalLeaseNodeNotConfiguredError", { enumerable: true, get: function () { return errors_js_1.PersonalLeaseNodeNotConfiguredError; } });
|
|
33
|
-
Object.defineProperty(exports, "P2PQuorumNotImplementedError", { enumerable: true, get: function () { return errors_js_1.P2PQuorumNotImplementedError; } });
|
|
34
|
-
Object.defineProperty(exports, "OnchainWatermarkNotImplementedError", { enumerable: true, get: function () { return errors_js_1.OnchainWatermarkNotImplementedError; } });
|
|
35
|
-
Object.defineProperty(exports, "QuorumUnavailableError", { enumerable: true, get: function () { return errors_js_1.QuorumUnavailableError; } });
|
|
36
|
-
Object.defineProperty(exports, "QuorumConflictError", { enumerable: true, get: function () { return errors_js_1.QuorumConflictError; } });
|
|
37
|
-
Object.defineProperty(exports, "OnchainWatermarkError", { enumerable: true, get: function () { return errors_js_1.OnchainWatermarkError; } });
|
|
38
|
-
Object.defineProperty(exports, "DeviceRangeViolationError", { enumerable: true, get: function () { return errors_js_1.DeviceRangeViolationError; } });
|
|
1
|
+
export { WotsWatermarkStore, flatIndex, fromFlatIndex, } from './watermark.js';
|
|
2
|
+
export { LeaseJournal } from './journal.js';
|
|
3
|
+
export { LocalLeaseProvider } from './local.js';
|
|
4
|
+
export { seedLeaseWatermark, exportLeaseWatermark } from './seed.js';
|
|
5
|
+
export { AxiaLeaseProvider } from './axia.js';
|
|
6
|
+
export { HybridLeaseProvider } from './hybrid.js';
|
|
7
|
+
export { PersonalLeaseNodeProvider, P2PQuorumLeaseProvider, OnchainWatermarkProvider, } from './stubs.js';
|
|
8
|
+
export { P2PQuorumLeaseProvider as QuorumLeaseProvider } from './quorum.js';
|
|
9
|
+
export { OnchainWatermarkProvider as ChainWatermarkProvider } from './onchain.js';
|
|
10
|
+
export { allocateDeviceRange, deviceSlotForAddressIndex } from './device.js';
|
|
11
|
+
export { WatermarkMonotonicityError, WatermarkExhaustedError, WatermarkSeedRegressionError, WatermarkSeedRequiredError, LeaseNotFoundError, IndicesUnavailableError, PersonalLeaseNodeNotConfiguredError, P2PQuorumNotImplementedError, OnchainWatermarkNotImplementedError, QuorumUnavailableError, QuorumConflictError, OnchainWatermarkError, DeviceRangeViolationError, } from './errors.js';
|
|
12
|
+
export { ReplicatedLeaseJournalBackup } from './replicated-backup.js';
|
package/dist/journal.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* LeaseJournal — append-only audit log for WOTS key-use events.
|
|
3
|
-
*
|
|
2
|
+
* LeaseJournal — physically append-only audit log for WOTS key-use events.
|
|
3
|
+
*
|
|
4
|
+
* Layout v1 stores one immutable record per sequence. The legacy whole-array
|
|
5
|
+
* key is retained as migration input/forensic history but is never rewritten.
|
|
6
|
+
* The SHA-256 chain format is intentionally unchanged (RFC-007 OQ3).
|
|
4
7
|
*/
|
|
5
8
|
import type { StorageAdapter, LoggerAdapter } from '@totemsdk/core';
|
|
6
9
|
import type { JournalEntry } from './types.js';
|
|
@@ -8,11 +11,18 @@ export declare class LeaseJournal {
|
|
|
8
11
|
private readonly storage;
|
|
9
12
|
private readonly logger;
|
|
10
13
|
private entries;
|
|
11
|
-
private
|
|
14
|
+
private initialized;
|
|
15
|
+
private initializePromise;
|
|
16
|
+
private appendTail;
|
|
12
17
|
constructor(storage: StorageAdapter, logger?: LoggerAdapter);
|
|
13
18
|
initialize(): Promise<void>;
|
|
19
|
+
private initializeOnce;
|
|
20
|
+
private readLegacyEntries;
|
|
21
|
+
private readPhysicalRecords;
|
|
22
|
+
private writeRecord;
|
|
14
23
|
append(entry: JournalEntry): Promise<void>;
|
|
15
|
-
private
|
|
24
|
+
private appendOne;
|
|
25
|
+
private ensureInitialized;
|
|
16
26
|
getAll(): JournalEntry[];
|
|
17
27
|
getByTree(treeId: string): JournalEntry[];
|
|
18
28
|
getByReservation(reservationId: string): JournalEntry | undefined;
|