@optimystic/db-p2p 0.0.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/dist/index.min.js +52 -0
- package/dist/index.min.js.map +7 -0
- package/dist/src/cluster/client.d.ts +12 -0
- package/dist/src/cluster/client.d.ts.map +1 -0
- package/dist/src/cluster/client.js +65 -0
- package/dist/src/cluster/client.js.map +1 -0
- package/dist/src/cluster/cluster-repo.d.ts +79 -0
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -0
- package/dist/src/cluster/cluster-repo.js +613 -0
- package/dist/src/cluster/cluster-repo.js.map +1 -0
- package/dist/src/cluster/partition-detector.d.ts +59 -0
- package/dist/src/cluster/partition-detector.d.ts.map +1 -0
- package/dist/src/cluster/partition-detector.js +129 -0
- package/dist/src/cluster/partition-detector.js.map +1 -0
- package/dist/src/cluster/service.d.ts +49 -0
- package/dist/src/cluster/service.d.ts.map +1 -0
- package/dist/src/cluster/service.js +107 -0
- package/dist/src/cluster/service.js.map +1 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +29 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/it-utility.d.ts +4 -0
- package/dist/src/it-utility.d.ts.map +1 -0
- package/dist/src/it-utility.js +32 -0
- package/dist/src/it-utility.js.map +1 -0
- package/dist/src/libp2p-key-network.d.ts +59 -0
- package/dist/src/libp2p-key-network.d.ts.map +1 -0
- package/dist/src/libp2p-key-network.js +278 -0
- package/dist/src/libp2p-key-network.js.map +1 -0
- package/dist/src/libp2p-node.d.ts +28 -0
- package/dist/src/libp2p-node.d.ts.map +1 -0
- package/dist/src/libp2p-node.js +270 -0
- package/dist/src/libp2p-node.js.map +1 -0
- package/dist/src/logger.d.ts +3 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +6 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/network/get-network-manager.d.ts +4 -0
- package/dist/src/network/get-network-manager.d.ts.map +1 -0
- package/dist/src/network/get-network-manager.js +17 -0
- package/dist/src/network/get-network-manager.js.map +1 -0
- package/dist/src/network/network-manager-service.d.ts +82 -0
- package/dist/src/network/network-manager-service.d.ts.map +1 -0
- package/dist/src/network/network-manager-service.js +283 -0
- package/dist/src/network/network-manager-service.js.map +1 -0
- package/dist/src/peer-utils.d.ts +2 -0
- package/dist/src/peer-utils.d.ts.map +1 -0
- package/dist/src/peer-utils.js +28 -0
- package/dist/src/peer-utils.js.map +1 -0
- package/dist/src/protocol-client.d.ts +12 -0
- package/dist/src/protocol-client.d.ts.map +1 -0
- package/dist/src/protocol-client.js +34 -0
- package/dist/src/protocol-client.js.map +1 -0
- package/dist/src/repo/client.d.ts +17 -0
- package/dist/src/repo/client.d.ts.map +1 -0
- package/dist/src/repo/client.js +82 -0
- package/dist/src/repo/client.js.map +1 -0
- package/dist/src/repo/cluster-coordinator.d.ts +59 -0
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -0
- package/dist/src/repo/cluster-coordinator.js +539 -0
- package/dist/src/repo/cluster-coordinator.js.map +1 -0
- package/dist/src/repo/coordinator-repo.d.ts +29 -0
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -0
- package/dist/src/repo/coordinator-repo.js +102 -0
- package/dist/src/repo/coordinator-repo.js.map +1 -0
- package/dist/src/repo/redirect.d.ts +14 -0
- package/dist/src/repo/redirect.d.ts.map +1 -0
- package/dist/src/repo/redirect.js +9 -0
- package/dist/src/repo/redirect.js.map +1 -0
- package/dist/src/repo/service.d.ts +52 -0
- package/dist/src/repo/service.d.ts.map +1 -0
- package/dist/src/repo/service.js +181 -0
- package/dist/src/repo/service.js.map +1 -0
- package/dist/src/repo/types.d.ts +7 -0
- package/dist/src/repo/types.d.ts.map +1 -0
- package/dist/src/repo/types.js +2 -0
- package/dist/src/repo/types.js.map +1 -0
- package/dist/src/routing/libp2p-known-peers.d.ts +4 -0
- package/dist/src/routing/libp2p-known-peers.d.ts.map +1 -0
- package/dist/src/routing/libp2p-known-peers.js +19 -0
- package/dist/src/routing/libp2p-known-peers.js.map +1 -0
- package/dist/src/routing/responsibility.d.ts +14 -0
- package/dist/src/routing/responsibility.d.ts.map +1 -0
- package/dist/src/routing/responsibility.js +45 -0
- package/dist/src/routing/responsibility.js.map +1 -0
- package/dist/src/routing/simple-cluster-coordinator.d.ts +23 -0
- package/dist/src/routing/simple-cluster-coordinator.d.ts.map +1 -0
- package/dist/src/routing/simple-cluster-coordinator.js +59 -0
- package/dist/src/routing/simple-cluster-coordinator.js.map +1 -0
- package/dist/src/storage/arachnode-fret-adapter.d.ts +65 -0
- package/dist/src/storage/arachnode-fret-adapter.d.ts.map +1 -0
- package/dist/src/storage/arachnode-fret-adapter.js +93 -0
- package/dist/src/storage/arachnode-fret-adapter.js.map +1 -0
- package/dist/src/storage/block-storage.d.ts +31 -0
- package/dist/src/storage/block-storage.d.ts.map +1 -0
- package/dist/src/storage/block-storage.js +154 -0
- package/dist/src/storage/block-storage.js.map +1 -0
- package/dist/src/storage/file-storage.d.ts +30 -0
- package/dist/src/storage/file-storage.d.ts.map +1 -0
- package/dist/src/storage/file-storage.js +127 -0
- package/dist/src/storage/file-storage.js.map +1 -0
- package/dist/src/storage/helpers.d.ts +3 -0
- package/dist/src/storage/helpers.d.ts.map +1 -0
- package/dist/src/storage/helpers.js +28 -0
- package/dist/src/storage/helpers.js.map +1 -0
- package/dist/src/storage/i-block-storage.d.ts +32 -0
- package/dist/src/storage/i-block-storage.d.ts.map +1 -0
- package/dist/src/storage/i-block-storage.js +2 -0
- package/dist/src/storage/i-block-storage.js.map +1 -0
- package/dist/src/storage/i-raw-storage.d.ts +20 -0
- package/dist/src/storage/i-raw-storage.d.ts.map +1 -0
- package/dist/src/storage/i-raw-storage.js +2 -0
- package/dist/src/storage/i-raw-storage.js.map +1 -0
- package/dist/src/storage/memory-storage.d.ts +27 -0
- package/dist/src/storage/memory-storage.d.ts.map +1 -0
- package/dist/src/storage/memory-storage.js +87 -0
- package/dist/src/storage/memory-storage.js.map +1 -0
- package/dist/src/storage/restoration-coordinator-v2.d.ts +63 -0
- package/dist/src/storage/restoration-coordinator-v2.d.ts.map +1 -0
- package/dist/src/storage/restoration-coordinator-v2.js +157 -0
- package/dist/src/storage/restoration-coordinator-v2.js.map +1 -0
- package/dist/src/storage/ring-selector.d.ts +56 -0
- package/dist/src/storage/ring-selector.d.ts.map +1 -0
- package/dist/src/storage/ring-selector.js +118 -0
- package/dist/src/storage/ring-selector.js.map +1 -0
- package/dist/src/storage/storage-monitor.d.ts +23 -0
- package/dist/src/storage/storage-monitor.d.ts.map +1 -0
- package/dist/src/storage/storage-monitor.js +40 -0
- package/dist/src/storage/storage-monitor.js.map +1 -0
- package/dist/src/storage/storage-repo.d.ts +17 -0
- package/dist/src/storage/storage-repo.d.ts.map +1 -0
- package/dist/src/storage/storage-repo.js +267 -0
- package/dist/src/storage/storage-repo.js.map +1 -0
- package/dist/src/storage/struct.d.ts +29 -0
- package/dist/src/storage/struct.d.ts.map +1 -0
- package/dist/src/storage/struct.js +2 -0
- package/dist/src/storage/struct.js.map +1 -0
- package/dist/src/sync/client.d.ts +27 -0
- package/dist/src/sync/client.d.ts.map +1 -0
- package/dist/src/sync/client.js +32 -0
- package/dist/src/sync/client.js.map +1 -0
- package/dist/src/sync/protocol.d.ts +58 -0
- package/dist/src/sync/protocol.d.ts.map +1 -0
- package/dist/src/sync/protocol.js +12 -0
- package/dist/src/sync/protocol.js.map +1 -0
- package/dist/src/sync/service.d.ts +62 -0
- package/dist/src/sync/service.d.ts.map +1 -0
- package/dist/src/sync/service.js +168 -0
- package/dist/src/sync/service.js.map +1 -0
- package/package.json +73 -0
- package/readme.md +497 -0
- package/src/cluster/client.ts +63 -0
- package/src/cluster/cluster-repo.ts +711 -0
- package/src/cluster/partition-detector.ts +158 -0
- package/src/cluster/service.ts +156 -0
- package/src/index.ts +30 -0
- package/src/it-utility.ts +36 -0
- package/src/libp2p-key-network.ts +334 -0
- package/src/libp2p-node.ts +335 -0
- package/src/logger.ts +9 -0
- package/src/network/get-network-manager.ts +17 -0
- package/src/network/network-manager-service.ts +334 -0
- package/src/peer-utils.ts +24 -0
- package/src/protocol-client.ts +54 -0
- package/src/repo/client.ts +112 -0
- package/src/repo/cluster-coordinator.ts +592 -0
- package/src/repo/coordinator-repo.ts +137 -0
- package/src/repo/redirect.ts +17 -0
- package/src/repo/service.ts +219 -0
- package/src/repo/types.ts +7 -0
- package/src/routing/libp2p-known-peers.ts +26 -0
- package/src/routing/responsibility.ts +63 -0
- package/src/routing/simple-cluster-coordinator.ts +70 -0
- package/src/storage/arachnode-fret-adapter.ts +128 -0
- package/src/storage/block-storage.ts +182 -0
- package/src/storage/file-storage.ts +163 -0
- package/src/storage/helpers.ts +29 -0
- package/src/storage/i-block-storage.ts +40 -0
- package/src/storage/i-raw-storage.ts +30 -0
- package/src/storage/memory-storage.ts +108 -0
- package/src/storage/restoration-coordinator-v2.ts +191 -0
- package/src/storage/ring-selector.ts +155 -0
- package/src/storage/storage-monitor.ts +59 -0
- package/src/storage/storage-repo.ts +320 -0
- package/src/storage/struct.ts +34 -0
- package/src/sync/client.ts +42 -0
- package/src/sync/protocol.ts +71 -0
- package/src/sync/service.ts +229 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
import { blockIdsForTransforms } from "@optimystic/db-core";
|
|
2
|
+
import { ClusterClient } from "./client.js";
|
|
3
|
+
import { peerIdFromString } from "@libp2p/peer-id";
|
|
4
|
+
import { sha256 } from "multiformats/hashes/sha2";
|
|
5
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
|
6
|
+
import { createLogger } from '../logger.js';
|
|
7
|
+
const log = createLogger('cluster-member');
|
|
8
|
+
/** State of a transaction in the cluster */
|
|
9
|
+
var TransactionPhase;
|
|
10
|
+
(function (TransactionPhase) {
|
|
11
|
+
TransactionPhase[TransactionPhase["Promising"] = 0] = "Promising";
|
|
12
|
+
TransactionPhase[TransactionPhase["OurPromiseNeeded"] = 1] = "OurPromiseNeeded";
|
|
13
|
+
TransactionPhase[TransactionPhase["OurCommitNeeded"] = 2] = "OurCommitNeeded";
|
|
14
|
+
TransactionPhase[TransactionPhase["Consensus"] = 3] = "Consensus";
|
|
15
|
+
TransactionPhase[TransactionPhase["Rejected"] = 4] = "Rejected";
|
|
16
|
+
TransactionPhase[TransactionPhase["Propagating"] = 5] = "Propagating"; // Transaction is being propagated
|
|
17
|
+
})(TransactionPhase || (TransactionPhase = {}));
|
|
18
|
+
export function clusterMember(components) {
|
|
19
|
+
return new ClusterMember(components.storageRepo, components.peerNetwork, components.peerId, components.protocolPrefix, components.partitionDetector, components.fretService, components.validator);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Handles cluster-side operations, managing promises and commits for cluster updates
|
|
23
|
+
* and coordinating with the local storage repo.
|
|
24
|
+
*/
|
|
25
|
+
export class ClusterMember {
|
|
26
|
+
storageRepo;
|
|
27
|
+
peerNetwork;
|
|
28
|
+
peerId;
|
|
29
|
+
protocolPrefix;
|
|
30
|
+
partitionDetector;
|
|
31
|
+
fretService;
|
|
32
|
+
validator;
|
|
33
|
+
// Track active transactions by their message hash
|
|
34
|
+
activeTransactions = new Map();
|
|
35
|
+
// Queue of transactions to clean up
|
|
36
|
+
cleanupQueue = [];
|
|
37
|
+
// Serialize concurrent updates for the same transaction
|
|
38
|
+
pendingUpdates = new Map();
|
|
39
|
+
constructor(storageRepo, peerNetwork, peerId, protocolPrefix, partitionDetector, fretService, validator) {
|
|
40
|
+
this.storageRepo = storageRepo;
|
|
41
|
+
this.peerNetwork = peerNetwork;
|
|
42
|
+
this.peerId = peerId;
|
|
43
|
+
this.protocolPrefix = protocolPrefix;
|
|
44
|
+
this.partitionDetector = partitionDetector;
|
|
45
|
+
this.fretService = fretService;
|
|
46
|
+
this.validator = validator;
|
|
47
|
+
// Periodically clean up expired transactions
|
|
48
|
+
setInterval(() => this.queueExpiredTransactions(), 60000);
|
|
49
|
+
// Process cleanup queue
|
|
50
|
+
setInterval(() => this.processCleanupQueue(), 1000);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Handles an incoming cluster update, managing the two-phase commit process
|
|
54
|
+
* and coordinating with the local storage repo
|
|
55
|
+
*/
|
|
56
|
+
async update(record) {
|
|
57
|
+
// Serialize concurrent updates for the same transaction
|
|
58
|
+
const existingUpdate = this.pendingUpdates.get(record.messageHash);
|
|
59
|
+
if (existingUpdate) {
|
|
60
|
+
log('cluster-member:concurrent-update-wait', { messageHash: record.messageHash });
|
|
61
|
+
await existingUpdate;
|
|
62
|
+
// After waiting, continue processing with the new incoming record
|
|
63
|
+
// to ensure proper merging of promises/commits from coordinator
|
|
64
|
+
}
|
|
65
|
+
// Create a promise for this update operation
|
|
66
|
+
const updatePromise = this.processUpdate(record);
|
|
67
|
+
this.pendingUpdates.set(record.messageHash, updatePromise);
|
|
68
|
+
try {
|
|
69
|
+
const result = await updatePromise;
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
// Remove from pending updates after a short delay to allow concurrent calls to see it
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
this.pendingUpdates.delete(record.messageHash);
|
|
76
|
+
}, 100);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async processUpdate(record) {
|
|
80
|
+
const ourId = this.peerId.toString();
|
|
81
|
+
const inboundPhase = record.commits[ourId] ? 'commit' : record.promises[ourId] ? 'promise' : 'initial';
|
|
82
|
+
log('cluster-member:incoming', {
|
|
83
|
+
messageHash: record.messageHash,
|
|
84
|
+
phase: inboundPhase,
|
|
85
|
+
peerCount: Object.keys(record.peers).length,
|
|
86
|
+
promiseCount: Object.keys(record.promises).length,
|
|
87
|
+
commitCount: Object.keys(record.commits).length,
|
|
88
|
+
existingTransaction: this.activeTransactions.has(record.messageHash)
|
|
89
|
+
});
|
|
90
|
+
// Report network size hint to FRET if provided
|
|
91
|
+
if (this.fretService && record.networkSizeHint && record.networkSizeConfidence) {
|
|
92
|
+
try {
|
|
93
|
+
this.fretService.reportNetworkSize(record.networkSizeHint, record.networkSizeConfidence, 'cluster');
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
// Ignore errors reporting to FRET
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Validate the incoming record
|
|
100
|
+
await this.validateRecord(record);
|
|
101
|
+
const existingState = this.activeTransactions.get(record.messageHash);
|
|
102
|
+
let currentRecord = existingState?.record || record;
|
|
103
|
+
if (existingState) {
|
|
104
|
+
log('cluster-member:merge-start', {
|
|
105
|
+
messageHash: record.messageHash,
|
|
106
|
+
existingPromises: Object.keys(existingState.record.promises ?? {}),
|
|
107
|
+
existingCommits: Object.keys(existingState.record.commits ?? {}),
|
|
108
|
+
incomingPromises: Object.keys(record.promises ?? {}),
|
|
109
|
+
incomingCommits: Object.keys(record.commits ?? {})
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// If we have an existing record, merge the signatures
|
|
113
|
+
if (existingState) {
|
|
114
|
+
currentRecord = await this.mergeRecords(existingState.record, record);
|
|
115
|
+
log('cluster-member:merge-complete', {
|
|
116
|
+
messageHash: record.messageHash,
|
|
117
|
+
mergedPromises: Object.keys(currentRecord.promises ?? {}),
|
|
118
|
+
mergedCommits: Object.keys(currentRecord.commits ?? {})
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// Get the current transaction state
|
|
122
|
+
const phase = await this.getTransactionPhase(currentRecord);
|
|
123
|
+
log('cluster-member:phase', {
|
|
124
|
+
messageHash: record.messageHash,
|
|
125
|
+
phase,
|
|
126
|
+
promises: Object.keys(currentRecord.promises ?? {}),
|
|
127
|
+
commits: Object.keys(currentRecord.commits ?? {})
|
|
128
|
+
});
|
|
129
|
+
let shouldPersist = true;
|
|
130
|
+
// Handle the transaction based on its state
|
|
131
|
+
switch (phase) {
|
|
132
|
+
case TransactionPhase.OurPromiseNeeded:
|
|
133
|
+
log('cluster-member:action-promise', {
|
|
134
|
+
messageHash: record.messageHash
|
|
135
|
+
});
|
|
136
|
+
currentRecord = await this.handlePromiseNeeded(currentRecord);
|
|
137
|
+
log('cluster-member:action-promise-complete', {
|
|
138
|
+
messageHash: record.messageHash,
|
|
139
|
+
promises: Object.keys(currentRecord.promises ?? {})
|
|
140
|
+
});
|
|
141
|
+
break;
|
|
142
|
+
case TransactionPhase.OurCommitNeeded:
|
|
143
|
+
log('cluster-member:action-commit', {
|
|
144
|
+
messageHash: record.messageHash
|
|
145
|
+
});
|
|
146
|
+
currentRecord = await this.handleCommitNeeded(currentRecord);
|
|
147
|
+
log('cluster-member:action-commit-complete', {
|
|
148
|
+
messageHash: record.messageHash,
|
|
149
|
+
commits: Object.keys(currentRecord.commits ?? {})
|
|
150
|
+
});
|
|
151
|
+
// After adding our commit, clear the transaction - the coordinator will handle consensus
|
|
152
|
+
shouldPersist = false;
|
|
153
|
+
break;
|
|
154
|
+
case TransactionPhase.Consensus:
|
|
155
|
+
log('cluster-member:action-consensus', {
|
|
156
|
+
messageHash: record.messageHash
|
|
157
|
+
});
|
|
158
|
+
await this.handleConsensus(currentRecord);
|
|
159
|
+
// Don't call clearTransaction here - it happens in handleConsensus
|
|
160
|
+
shouldPersist = false;
|
|
161
|
+
break;
|
|
162
|
+
case TransactionPhase.Rejected:
|
|
163
|
+
log('cluster-member:action-rejected', {
|
|
164
|
+
messageHash: record.messageHash
|
|
165
|
+
});
|
|
166
|
+
// Don't call clearTransaction here - it happens in handleRejection
|
|
167
|
+
await this.handleRejection(currentRecord);
|
|
168
|
+
shouldPersist = false;
|
|
169
|
+
break;
|
|
170
|
+
case TransactionPhase.Propagating:
|
|
171
|
+
// Transaction is complete and propagating - clean it up
|
|
172
|
+
log('cluster-member:phase-propagating', {
|
|
173
|
+
messageHash: record.messageHash
|
|
174
|
+
});
|
|
175
|
+
shouldPersist = false;
|
|
176
|
+
break;
|
|
177
|
+
case TransactionPhase.Promising:
|
|
178
|
+
// Still collecting promises from peers - if we haven't added ours and there's no conflict, add it
|
|
179
|
+
// This state shouldn't normally be reached since OurPromiseNeeded is checked first
|
|
180
|
+
log('cluster-member:phase-promising-blocked', {
|
|
181
|
+
messageHash: record.messageHash
|
|
182
|
+
});
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
if (shouldPersist) {
|
|
186
|
+
// Update transaction state
|
|
187
|
+
const timeouts = this.setupTimeouts(currentRecord);
|
|
188
|
+
this.activeTransactions.set(record.messageHash, {
|
|
189
|
+
record: currentRecord,
|
|
190
|
+
lastUpdate: Date.now(),
|
|
191
|
+
promiseTimeout: timeouts.promiseTimeout,
|
|
192
|
+
resolutionTimeout: timeouts.resolutionTimeout
|
|
193
|
+
});
|
|
194
|
+
log('cluster-member:state-persist', {
|
|
195
|
+
messageHash: record.messageHash,
|
|
196
|
+
storedPromises: Object.keys(currentRecord.promises ?? {}),
|
|
197
|
+
storedCommits: Object.keys(currentRecord.commits ?? {})
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
log('cluster-member:state-clear', {
|
|
202
|
+
messageHash: record.messageHash
|
|
203
|
+
});
|
|
204
|
+
this.clearTransaction(record.messageHash);
|
|
205
|
+
}
|
|
206
|
+
// Skip propagation - the coordinator manages distribution
|
|
207
|
+
// await this.propagateIfNeeded(currentRecord);
|
|
208
|
+
log('cluster-member:update-complete', {
|
|
209
|
+
messageHash: record.messageHash,
|
|
210
|
+
promiseCount: Object.keys(currentRecord.promises).length,
|
|
211
|
+
commitCount: Object.keys(currentRecord.commits).length
|
|
212
|
+
});
|
|
213
|
+
return currentRecord;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Merges two records, validating that non-signature fields match
|
|
217
|
+
*/
|
|
218
|
+
async mergeRecords(existing, incoming) {
|
|
219
|
+
log('cluster-member:merge-records', {
|
|
220
|
+
messageHash: existing.messageHash,
|
|
221
|
+
existingPromises: Object.keys(existing.promises ?? {}),
|
|
222
|
+
existingCommits: Object.keys(existing.commits ?? {}),
|
|
223
|
+
incomingPromises: Object.keys(incoming.promises ?? {}),
|
|
224
|
+
incomingCommits: Object.keys(incoming.commits ?? {})
|
|
225
|
+
});
|
|
226
|
+
// Verify that immutable fields match
|
|
227
|
+
if (existing.messageHash !== incoming.messageHash) {
|
|
228
|
+
throw new Error('Message hash mismatch');
|
|
229
|
+
}
|
|
230
|
+
if (JSON.stringify(existing.message) !== JSON.stringify(incoming.message)) {
|
|
231
|
+
throw new Error('Message content mismatch');
|
|
232
|
+
}
|
|
233
|
+
if (JSON.stringify(existing.peers) !== JSON.stringify(incoming.peers)) {
|
|
234
|
+
throw new Error('Peers mismatch');
|
|
235
|
+
}
|
|
236
|
+
// Merge signatures, keeping the most recent valid ones
|
|
237
|
+
return {
|
|
238
|
+
...existing,
|
|
239
|
+
promises: { ...existing.promises, ...incoming.promises },
|
|
240
|
+
commits: { ...existing.commits, ...incoming.commits }
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async validateRecord(record) {
|
|
244
|
+
// TODO: Fix hash validation logic to match coordinator's hash generation
|
|
245
|
+
// The coordinator creates the hash from the message, but this tries to re-hash the hash itself
|
|
246
|
+
// Validate signatures
|
|
247
|
+
await this.validateSignatures(record);
|
|
248
|
+
// Validate expiration
|
|
249
|
+
if (record.message.expiration && record.message.expiration < Date.now()) {
|
|
250
|
+
throw new Error('Transaction expired');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async computeMessageHash(record) {
|
|
254
|
+
const msgBytes = new TextEncoder().encode(record.messageHash + JSON.stringify(record.message));
|
|
255
|
+
const hashBytes = await sha256.digest(msgBytes);
|
|
256
|
+
return uint8ArrayToString(hashBytes.digest, 'base64url');
|
|
257
|
+
}
|
|
258
|
+
async validateSignatures(record) {
|
|
259
|
+
// Validate promise signatures
|
|
260
|
+
const promiseHash = await this.computePromiseHash(record);
|
|
261
|
+
for (const [peerId, signature] of Object.entries(record.promises)) {
|
|
262
|
+
if (!await this.verifySignature(peerId, promiseHash, signature)) {
|
|
263
|
+
throw new Error(`Invalid promise signature from ${peerId}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Validate commit signatures
|
|
267
|
+
const commitHash = await this.computeCommitHash(record);
|
|
268
|
+
for (const [peerId, signature] of Object.entries(record.commits)) {
|
|
269
|
+
if (!await this.verifySignature(peerId, commitHash, signature)) {
|
|
270
|
+
throw new Error(`Invalid commit signature from ${peerId}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async computePromiseHash(record) {
|
|
275
|
+
const msgBytes = new TextEncoder().encode(record.messageHash + JSON.stringify(record.message));
|
|
276
|
+
const hashBytes = await sha256.digest(msgBytes);
|
|
277
|
+
return uint8ArrayToString(hashBytes.digest, 'base64url');
|
|
278
|
+
}
|
|
279
|
+
async computeCommitHash(record) {
|
|
280
|
+
const msgBytes = new TextEncoder().encode(record.messageHash + JSON.stringify(record.message) + JSON.stringify(record.promises));
|
|
281
|
+
const hashBytes = await sha256.digest(msgBytes);
|
|
282
|
+
return uint8ArrayToString(hashBytes.digest, 'base64url');
|
|
283
|
+
}
|
|
284
|
+
async verifySignature(peerId, hash, signature) {
|
|
285
|
+
// TODO: Implement actual signature verification
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
async getTransactionPhase(record) {
|
|
289
|
+
const peerCount = Object.keys(record.peers).length;
|
|
290
|
+
const promiseCount = Object.keys(record.promises).length;
|
|
291
|
+
const commitCount = Object.keys(record.commits).length;
|
|
292
|
+
const ourId = this.peerId.toString();
|
|
293
|
+
// Check for rejections
|
|
294
|
+
const rejectedPromises = Object.values(record.promises).filter(s => s.type === 'reject');
|
|
295
|
+
const rejectedCommits = Object.values(record.commits).filter(s => s.type === 'reject');
|
|
296
|
+
if (rejectedPromises.length > 0 || this.hasMajority(rejectedCommits.length, peerCount)) {
|
|
297
|
+
return TransactionPhase.Rejected;
|
|
298
|
+
}
|
|
299
|
+
// Check if we need to promise
|
|
300
|
+
if (!record.promises[ourId] && !this.hasConflict(record)) {
|
|
301
|
+
return TransactionPhase.OurPromiseNeeded;
|
|
302
|
+
}
|
|
303
|
+
// Check if still collecting promises
|
|
304
|
+
if (promiseCount < peerCount) {
|
|
305
|
+
return TransactionPhase.Promising;
|
|
306
|
+
}
|
|
307
|
+
// Check if we need to commit
|
|
308
|
+
if (promiseCount === peerCount && !record.commits[ourId]) {
|
|
309
|
+
return TransactionPhase.OurCommitNeeded;
|
|
310
|
+
}
|
|
311
|
+
// Check for consensus
|
|
312
|
+
const approvedCommits = Object.values(record.commits).filter(s => s.type === 'approve');
|
|
313
|
+
if (this.hasMajority(approvedCommits.length, peerCount)) {
|
|
314
|
+
return TransactionPhase.Consensus;
|
|
315
|
+
}
|
|
316
|
+
return TransactionPhase.Propagating;
|
|
317
|
+
}
|
|
318
|
+
hasMajority(count, total) {
|
|
319
|
+
return count > total / 2;
|
|
320
|
+
}
|
|
321
|
+
async handlePromiseNeeded(record) {
|
|
322
|
+
// Validate pend operations if we have a validator
|
|
323
|
+
const validationResult = await this.validatePendOperations(record);
|
|
324
|
+
const signature = validationResult.valid
|
|
325
|
+
? { type: 'approve', signature: 'approved' }
|
|
326
|
+
: { type: 'reject', signature: 'rejected', rejectReason: validationResult.reason };
|
|
327
|
+
if (!validationResult.valid) {
|
|
328
|
+
log('cluster-member:validation-rejected', {
|
|
329
|
+
messageHash: record.messageHash,
|
|
330
|
+
reason: validationResult.reason
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
...record,
|
|
335
|
+
promises: {
|
|
336
|
+
...record.promises,
|
|
337
|
+
[this.peerId.toString()]: signature
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Validates pend operations in a cluster record using the transaction validator.
|
|
343
|
+
* Returns success if no validator is configured (backwards compatibility).
|
|
344
|
+
*/
|
|
345
|
+
async validatePendOperations(record) {
|
|
346
|
+
if (!this.validator) {
|
|
347
|
+
return { valid: true };
|
|
348
|
+
}
|
|
349
|
+
// Find pend operations in the message
|
|
350
|
+
for (const operation of record.message.operations) {
|
|
351
|
+
if ('pend' in operation) {
|
|
352
|
+
const pendRequest = operation.pend;
|
|
353
|
+
// Only validate if we have a transaction and operationsHash
|
|
354
|
+
if (pendRequest.transaction && pendRequest.operationsHash) {
|
|
355
|
+
const result = await this.validator.validate(pendRequest.transaction, pendRequest.operationsHash);
|
|
356
|
+
if (!result.valid) {
|
|
357
|
+
return { valid: false, reason: result.reason };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return { valid: true };
|
|
363
|
+
}
|
|
364
|
+
async handleCommitNeeded(record) {
|
|
365
|
+
if (this.hasLocalCommit(record)) {
|
|
366
|
+
return record;
|
|
367
|
+
}
|
|
368
|
+
const signature = {
|
|
369
|
+
type: 'approve',
|
|
370
|
+
signature: 'committed' // TODO: Actually sign the commit hash
|
|
371
|
+
};
|
|
372
|
+
return {
|
|
373
|
+
...record,
|
|
374
|
+
commits: {
|
|
375
|
+
...record.commits,
|
|
376
|
+
[this.peerId.toString()]: signature
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
async handleConsensus(record) {
|
|
381
|
+
// Execute the operations only if we haven't already
|
|
382
|
+
const state = this.activeTransactions.get(record.messageHash);
|
|
383
|
+
if (!this.hasLocalCommit(state?.record ?? record)) {
|
|
384
|
+
for (const operation of record.message.operations) {
|
|
385
|
+
if ('get' in operation) {
|
|
386
|
+
await this.storageRepo.get(operation.get);
|
|
387
|
+
}
|
|
388
|
+
else if ('pend' in operation) {
|
|
389
|
+
await this.storageRepo.pend(operation.pend);
|
|
390
|
+
}
|
|
391
|
+
else if ('commit' in operation) {
|
|
392
|
+
await this.storageRepo.commit(operation.commit);
|
|
393
|
+
}
|
|
394
|
+
else if ('cancel' in operation) {
|
|
395
|
+
await this.storageRepo.cancel(operation.cancel.actionRef);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
// Don't clear here - will be cleared by shouldPersist = false in the main flow
|
|
400
|
+
}
|
|
401
|
+
async handleRejection(record) {
|
|
402
|
+
// Clean up any resources - will be cleared by shouldPersist = false in the main flow
|
|
403
|
+
}
|
|
404
|
+
setupTimeouts(record) {
|
|
405
|
+
if (!record.message.expiration) {
|
|
406
|
+
return {};
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
promiseTimeout: setTimeout(() => this.handleExpiration(record.messageHash), record.message.expiration - Date.now()),
|
|
410
|
+
resolutionTimeout: setTimeout(() => this.resolveWithPeers(record.messageHash), record.message.expiration + 5000 - Date.now())
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
hasConflict(record) {
|
|
414
|
+
const now = Date.now();
|
|
415
|
+
const staleThresholdMs = 2000; // 2 seconds - allow more time for distributed consensus
|
|
416
|
+
for (const [existingHash, state] of Array.from(this.activeTransactions.entries())) {
|
|
417
|
+
if (existingHash === record.messageHash) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
// Clean up stale transactions that have been around too long
|
|
421
|
+
if (now - state.lastUpdate > staleThresholdMs) {
|
|
422
|
+
log('cluster-member:stale-cleanup', {
|
|
423
|
+
messageHash: existingHash,
|
|
424
|
+
age: now - state.lastUpdate
|
|
425
|
+
});
|
|
426
|
+
this.clearTransaction(existingHash);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (this.operationsConflict(state.record.message.operations, record.message.operations)) {
|
|
430
|
+
// Use race resolution to determine winner
|
|
431
|
+
const resolution = this.resolveRace(state.record, record);
|
|
432
|
+
if (resolution === 'keep-existing') {
|
|
433
|
+
log('cluster-member:race-keep-existing', {
|
|
434
|
+
existing: existingHash,
|
|
435
|
+
incoming: record.messageHash
|
|
436
|
+
});
|
|
437
|
+
return true; // Reject incoming
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// Accept incoming, abort existing
|
|
441
|
+
log('cluster-member:race-accept-incoming', {
|
|
442
|
+
existing: existingHash,
|
|
443
|
+
incoming: record.messageHash
|
|
444
|
+
});
|
|
445
|
+
this.clearTransaction(existingHash);
|
|
446
|
+
continue; // Check other conflicts
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return false; // No blocking conflicts
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Resolve race between two conflicting transactions.
|
|
454
|
+
* Transaction with more promises wins. If tied, higher hash wins.
|
|
455
|
+
*/
|
|
456
|
+
resolveRace(existing, incoming) {
|
|
457
|
+
const existingCount = Object.keys(existing.promises).length;
|
|
458
|
+
const incomingCount = Object.keys(incoming.promises).length;
|
|
459
|
+
// Transaction with more promises wins
|
|
460
|
+
if (existingCount > incomingCount) {
|
|
461
|
+
return 'keep-existing';
|
|
462
|
+
}
|
|
463
|
+
if (incomingCount > existingCount) {
|
|
464
|
+
return 'accept-incoming';
|
|
465
|
+
}
|
|
466
|
+
// Tie-breaker: higher message hash wins (deterministic)
|
|
467
|
+
return existing.messageHash > incoming.messageHash ? 'keep-existing' : 'accept-incoming';
|
|
468
|
+
}
|
|
469
|
+
operationsConflict(ops1, ops2) {
|
|
470
|
+
// Check if one is a commit for the same action as a pend - these don't conflict
|
|
471
|
+
const actionId1 = this.getActionId(ops1);
|
|
472
|
+
const actionId2 = this.getActionId(ops2);
|
|
473
|
+
if (actionId1 && actionId2 && actionId1 === actionId2) {
|
|
474
|
+
// Same action - commit is resolving the pend, not conflicting
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
const blocks1 = new Set(this.getAffectedBlockIds(ops1));
|
|
478
|
+
const blocks2 = new Set(this.getAffectedBlockIds(ops2));
|
|
479
|
+
for (const block of Array.from(blocks1)) {
|
|
480
|
+
if (blocks2.has(block)) {
|
|
481
|
+
log('cluster-member:conflict-detected', {
|
|
482
|
+
blocks1: Array.from(blocks1),
|
|
483
|
+
blocks2: Array.from(blocks2),
|
|
484
|
+
conflictingBlock: block
|
|
485
|
+
});
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
getActionId(operations) {
|
|
492
|
+
for (const operation of operations) {
|
|
493
|
+
if ('pend' in operation) {
|
|
494
|
+
return operation.pend.actionId;
|
|
495
|
+
}
|
|
496
|
+
else if ('commit' in operation) {
|
|
497
|
+
return operation.commit.actionId;
|
|
498
|
+
}
|
|
499
|
+
else if ('cancel' in operation) {
|
|
500
|
+
return operation.cancel.actionRef.actionId;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
getAffectedBlockIds(operations) {
|
|
506
|
+
const blockIds = new Set();
|
|
507
|
+
for (const operation of operations) {
|
|
508
|
+
if ('get' in operation) {
|
|
509
|
+
operation.get.blockIds.forEach(id => blockIds.add(id));
|
|
510
|
+
}
|
|
511
|
+
else if ('pend' in operation) {
|
|
512
|
+
// Use blockIdsForTransforms to correctly extract block IDs from Transforms structure
|
|
513
|
+
blockIdsForTransforms(operation.pend.transforms).forEach(id => blockIds.add(id));
|
|
514
|
+
}
|
|
515
|
+
else if ('commit' in operation) {
|
|
516
|
+
operation.commit.blockIds.forEach(id => blockIds.add(id));
|
|
517
|
+
}
|
|
518
|
+
else if ('cancel' in operation) {
|
|
519
|
+
operation.cancel.actionRef.blockIds.forEach(id => blockIds.add(id));
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return Array.from(blockIds);
|
|
523
|
+
}
|
|
524
|
+
async propagateIfNeeded(record) {
|
|
525
|
+
const promises = [];
|
|
526
|
+
for (const [peerId, peer] of Object.entries(record.peers)) {
|
|
527
|
+
if (peerId === this.peerId.toString())
|
|
528
|
+
continue;
|
|
529
|
+
try {
|
|
530
|
+
const client = ClusterClient.create(peerIdFromString(peerId), this.peerNetwork, this.protocolPrefix);
|
|
531
|
+
promises.push(client.update(record));
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
console.error(`Failed to propagate to peer ${peerId}:`, error);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
await Promise.allSettled(promises);
|
|
538
|
+
}
|
|
539
|
+
async handleExpiration(messageHash) {
|
|
540
|
+
const state = this.activeTransactions.get(messageHash);
|
|
541
|
+
if (!state)
|
|
542
|
+
return;
|
|
543
|
+
if (!state.record.promises[this.peerId.toString()]) {
|
|
544
|
+
const signature = {
|
|
545
|
+
type: 'reject',
|
|
546
|
+
signature: 'rejected',
|
|
547
|
+
rejectReason: 'Transaction expired'
|
|
548
|
+
};
|
|
549
|
+
const updatedRecord = {
|
|
550
|
+
...state.record,
|
|
551
|
+
promises: {
|
|
552
|
+
...state.record.promises,
|
|
553
|
+
[this.peerId.toString()]: signature
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
this.activeTransactions.set(messageHash, {
|
|
557
|
+
...state,
|
|
558
|
+
record: updatedRecord
|
|
559
|
+
});
|
|
560
|
+
await this.propagateIfNeeded(updatedRecord);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
async resolveWithPeers(messageHash) {
|
|
564
|
+
// This method is disabled - the coordinator handles all retry logic
|
|
565
|
+
// Keeping the skeleton in case we need peer-initiated recovery in the future
|
|
566
|
+
log('cluster-member:resolve-skipped', { messageHash, reason: 'coordinator-handles-retry' });
|
|
567
|
+
}
|
|
568
|
+
queueExpiredTransactions() {
|
|
569
|
+
const now = Date.now();
|
|
570
|
+
for (const [messageHash, state] of Array.from(this.activeTransactions.entries())) {
|
|
571
|
+
if (state.record.message.expiration && state.record.message.expiration < now) {
|
|
572
|
+
this.cleanupQueue.push(messageHash);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
async processCleanupQueue() {
|
|
577
|
+
while (this.cleanupQueue.length > 0) {
|
|
578
|
+
const messageHash = this.cleanupQueue.shift();
|
|
579
|
+
if (!messageHash)
|
|
580
|
+
continue;
|
|
581
|
+
const state = this.activeTransactions.get(messageHash);
|
|
582
|
+
if (!state)
|
|
583
|
+
continue;
|
|
584
|
+
const phase = await this.getTransactionPhase(state.record);
|
|
585
|
+
if (phase !== TransactionPhase.Consensus && phase !== TransactionPhase.Rejected) {
|
|
586
|
+
this.activeTransactions.delete(messageHash);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
hasLocalCommit(record) {
|
|
591
|
+
const ourId = this.peerId.toString();
|
|
592
|
+
return Boolean(record.commits[ourId]);
|
|
593
|
+
}
|
|
594
|
+
clearTransaction(messageHash) {
|
|
595
|
+
const state = this.activeTransactions.get(messageHash);
|
|
596
|
+
if (!state) {
|
|
597
|
+
log('cluster-member:clear-miss', { messageHash });
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (state.promiseTimeout) {
|
|
601
|
+
clearTimeout(state.promiseTimeout);
|
|
602
|
+
}
|
|
603
|
+
if (state.resolutionTimeout) {
|
|
604
|
+
clearTimeout(state.resolutionTimeout);
|
|
605
|
+
}
|
|
606
|
+
this.activeTransactions.delete(messageHash);
|
|
607
|
+
log('cluster-member:clear-done', {
|
|
608
|
+
messageHash,
|
|
609
|
+
remaining: Array.from(this.activeTransactions.keys())
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
//# sourceMappingURL=cluster-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster-repo.js","sourceRoot":"","sources":["../../../src/cluster/cluster-repo.ts"],"names":[],"mappings":"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"}
|