@optimystic/db-p2p 1.0.0-beta.3 → 1.1.0
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/src/cluster/block-transfer-service.d.ts +73 -1
- package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
- package/dist/src/cluster/block-transfer-service.js +70 -3
- package/dist/src/cluster/block-transfer-service.js.map +1 -1
- package/dist/src/cluster/block-transfer.d.ts +16 -1
- package/dist/src/cluster/block-transfer.d.ts.map +1 -1
- package/dist/src/cluster/block-transfer.js +73 -72
- package/dist/src/cluster/block-transfer.js.map +1 -1
- package/dist/src/cluster/client.d.ts +4 -6
- package/dist/src/cluster/client.d.ts.map +1 -1
- package/dist/src/cluster/client.js +8 -13
- package/dist/src/cluster/client.js.map +1 -1
- package/dist/src/cluster/cluster-policy.d.ts +2 -1
- package/dist/src/cluster/cluster-policy.d.ts.map +1 -1
- package/dist/src/cluster/cluster-policy.js.map +1 -1
- package/dist/src/cluster/cluster-repo.d.ts +155 -9
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +446 -58
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/commit-proof.js +2 -2
- package/dist/src/cluster/race-resolution.d.ts +51 -7
- package/dist/src/cluster/race-resolution.d.ts.map +1 -1
- package/dist/src/cluster/race-resolution.js +71 -7
- package/dist/src/cluster/race-resolution.js.map +1 -1
- package/dist/src/cluster/rebalance-monitor.d.ts +67 -5
- package/dist/src/cluster/rebalance-monitor.d.ts.map +1 -1
- package/dist/src/cluster/rebalance-monitor.js +120 -26
- package/dist/src/cluster/rebalance-monitor.js.map +1 -1
- package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
- package/dist/src/cluster/spread-on-churn.js +34 -47
- package/dist/src/cluster/spread-on-churn.js.map +1 -1
- package/dist/src/cohort-topic/host.d.ts.map +1 -1
- package/dist/src/cohort-topic/host.js +8 -6
- package/dist/src/cohort-topic/host.js.map +1 -1
- package/dist/src/cohort-topic/membership-source.js +1 -1
- package/dist/src/cohort-topic/membership-source.js.map +1 -1
- package/dist/src/cohort-topic/peer-codec.d.ts.map +1 -1
- package/dist/src/cohort-topic/peer-codec.js +5 -2
- package/dist/src/cohort-topic/peer-codec.js.map +1 -1
- package/dist/src/cohort-topic/stream-util.d.ts +24 -3
- package/dist/src/cohort-topic/stream-util.d.ts.map +1 -1
- package/dist/src/cohort-topic/stream-util.js +36 -3
- package/dist/src/cohort-topic/stream-util.js.map +1 -1
- package/dist/src/cohort-topic/topic-router.d.ts +9 -0
- package/dist/src/cohort-topic/topic-router.d.ts.map +1 -1
- package/dist/src/cohort-topic/topic-router.js +12 -2
- package/dist/src/cohort-topic/topic-router.js.map +1 -1
- package/dist/src/dispute/client.d.ts.map +1 -1
- package/dist/src/dispute/client.js +15 -3
- package/dist/src/dispute/client.js.map +1 -1
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p-key-network.d.ts +78 -17
- package/dist/src/libp2p-key-network.d.ts.map +1 -1
- package/dist/src/libp2p-key-network.js +234 -147
- package/dist/src/libp2p-key-network.js.map +1 -1
- package/dist/src/libp2p-node-base.d.ts +35 -1
- package/dist/src/libp2p-node-base.d.ts.map +1 -1
- package/dist/src/libp2p-node-base.js +151 -26
- package/dist/src/libp2p-node-base.js.map +1 -1
- package/dist/src/libp2p-node-rn.d.ts +2 -2
- package/dist/src/libp2p-node-rn.d.ts.map +1 -1
- package/dist/src/libp2p-node-rn.js.map +1 -1
- package/dist/src/libp2p-node.d.ts +2 -2
- package/dist/src/libp2p-node.d.ts.map +1 -1
- package/dist/src/libp2p-node.js.map +1 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/logger.js +6 -1
- package/dist/src/logger.js.map +1 -1
- package/dist/src/matchmaking/query-transport.d.ts +3 -4
- package/dist/src/matchmaking/query-transport.d.ts.map +1 -1
- package/dist/src/matchmaking/query-transport.js +9 -9
- package/dist/src/matchmaking/query-transport.js.map +1 -1
- package/dist/src/network/network-manager-service.d.ts +10 -5
- package/dist/src/network/network-manager-service.d.ts.map +1 -1
- package/dist/src/network/network-manager-service.js +11 -2
- package/dist/src/network/network-manager-service.js.map +1 -1
- package/dist/src/network/relay-reservation.d.ts +170 -0
- package/dist/src/network/relay-reservation.d.ts.map +1 -0
- package/dist/src/network/relay-reservation.js +527 -0
- package/dist/src/network/relay-reservation.js.map +1 -0
- package/dist/src/pend-validation.d.ts +3 -2
- package/dist/src/pend-validation.d.ts.map +1 -1
- package/dist/src/pend-validation.js +3 -2
- package/dist/src/pend-validation.js.map +1 -1
- package/dist/src/protocol-client.d.ts +8 -1
- package/dist/src/protocol-client.d.ts.map +1 -1
- package/dist/src/protocol-client.js +11 -0
- package/dist/src/protocol-client.js.map +1 -1
- package/dist/src/reactivity/forwarder-host.d.ts +2 -1
- package/dist/src/reactivity/forwarder-host.d.ts.map +1 -1
- package/dist/src/reactivity/forwarder-host.js +2 -1
- package/dist/src/reactivity/forwarder-host.js.map +1 -1
- package/dist/src/reactivity/origination-manager.d.ts +3 -3
- package/dist/src/reactivity/origination-manager.js +3 -3
- package/dist/src/reactivity/recover-transport.d.ts +22 -14
- package/dist/src/reactivity/recover-transport.d.ts.map +1 -1
- package/dist/src/reactivity/recover-transport.js +32 -19
- package/dist/src/reactivity/recover-transport.js.map +1 -1
- package/dist/src/reactivity/subscription-manager.d.ts +2 -2
- package/dist/src/reactivity/topic-bytes.d.ts +6 -7
- package/dist/src/reactivity/topic-bytes.d.ts.map +1 -1
- package/dist/src/reactivity/topic-bytes.js +8 -9
- package/dist/src/reactivity/topic-bytes.js.map +1 -1
- package/dist/src/repo/client.d.ts +5 -2
- package/dist/src/repo/client.d.ts.map +1 -1
- package/dist/src/repo/client.js +49 -40
- package/dist/src/repo/client.js.map +1 -1
- package/dist/src/repo/cluster-coordinator.d.ts +96 -11
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
- package/dist/src/repo/cluster-coordinator.js +164 -25
- package/dist/src/repo/cluster-coordinator.js.map +1 -1
- package/dist/src/repo/coordinator-repo.d.ts +240 -122
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
- package/dist/src/repo/coordinator-repo.js +627 -473
- package/dist/src/repo/coordinator-repo.js.map +1 -1
- package/dist/src/repo/i-under-replication-ledger.d.ts +87 -0
- package/dist/src/repo/i-under-replication-ledger.d.ts.map +1 -0
- package/dist/src/repo/i-under-replication-ledger.js +2 -0
- package/dist/src/repo/i-under-replication-ledger.js.map +1 -0
- package/dist/src/repo/kv-under-replication-ledger.d.ts +91 -0
- package/dist/src/repo/kv-under-replication-ledger.d.ts.map +1 -0
- package/dist/src/repo/kv-under-replication-ledger.js +287 -0
- package/dist/src/repo/kv-under-replication-ledger.js.map +1 -0
- package/dist/src/repo/responsibility.d.ts +37 -0
- package/dist/src/repo/responsibility.d.ts.map +1 -0
- package/dist/src/repo/responsibility.js +37 -0
- package/dist/src/repo/responsibility.js.map +1 -0
- package/dist/src/repo/service.d.ts +44 -15
- package/dist/src/repo/service.d.ts.map +1 -1
- package/dist/src/repo/service.js +64 -27
- package/dist/src/repo/service.js.map +1 -1
- package/dist/src/repo/stuck-reservation.d.ts +127 -0
- package/dist/src/repo/stuck-reservation.d.ts.map +1 -0
- package/dist/src/repo/stuck-reservation.js +179 -0
- package/dist/src/repo/stuck-reservation.js.map +1 -0
- package/dist/src/repo/under-replication-drain.d.ts +208 -0
- package/dist/src/repo/under-replication-drain.d.ts.map +1 -0
- package/dist/src/repo/under-replication-drain.js +461 -0
- package/dist/src/repo/under-replication-drain.js.map +1 -0
- package/dist/src/rn.d.ts +5 -0
- package/dist/src/rn.d.ts.map +1 -1
- package/dist/src/rn.js +5 -0
- package/dist/src/rn.js.map +1 -1
- package/dist/src/storage/block-latch.d.ts +3 -2
- package/dist/src/storage/block-latch.d.ts.map +1 -1
- package/dist/src/storage/block-latch.js +7 -4
- package/dist/src/storage/block-latch.js.map +1 -1
- package/dist/src/storage/block-storage.d.ts +45 -3
- package/dist/src/storage/block-storage.d.ts.map +1 -1
- package/dist/src/storage/block-storage.js +156 -9
- package/dist/src/storage/block-storage.js.map +1 -1
- package/dist/src/storage/i-block-storage.d.ts +57 -5
- package/dist/src/storage/i-block-storage.d.ts.map +1 -1
- package/dist/src/storage/i-block-storage.js.map +1 -1
- package/dist/src/storage/pending-claim.d.ts +167 -0
- package/dist/src/storage/pending-claim.d.ts.map +1 -0
- package/dist/src/storage/pending-claim.js +156 -0
- package/dist/src/storage/pending-claim.js.map +1 -0
- package/dist/src/storage/raw-store-codec.d.ts +13 -0
- package/dist/src/storage/raw-store-codec.d.ts.map +1 -1
- package/dist/src/storage/raw-store-codec.js +24 -3
- package/dist/src/storage/raw-store-codec.js.map +1 -1
- package/dist/src/storage/restoration-coordinator.d.ts.map +1 -1
- package/dist/src/storage/restoration-coordinator.js +2 -1
- package/dist/src/storage/restoration-coordinator.js.map +1 -1
- package/dist/src/storage/ring-shift-coordinator.d.ts.map +1 -1
- package/dist/src/storage/ring-shift-coordinator.js +3 -3
- package/dist/src/storage/ring-shift-coordinator.js.map +1 -1
- package/dist/src/storage/storage-repo.d.ts +122 -5
- package/dist/src/storage/storage-repo.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.js +245 -68
- package/dist/src/storage/storage-repo.js.map +1 -1
- package/dist/src/storage/struct.d.ts +58 -0
- package/dist/src/storage/struct.d.ts.map +1 -1
- package/dist/src/testing/mesh-harness.d.ts +77 -11
- package/dist/src/testing/mesh-harness.d.ts.map +1 -1
- package/dist/src/testing/mesh-harness.js +226 -100
- package/dist/src/testing/mesh-harness.js.map +1 -1
- package/package.json +2 -2
- package/readme.md +27 -3
- package/src/cluster/block-transfer-service.ts +132 -4
- package/src/cluster/block-transfer.ts +79 -84
- package/src/cluster/client.ts +115 -119
- package/src/cluster/cluster-policy.ts +2 -1
- package/src/cluster/cluster-repo.ts +493 -65
- package/src/cluster/commit-proof.ts +2 -2
- package/src/cluster/race-resolution.ts +76 -7
- package/src/cluster/rebalance-monitor.ts +677 -539
- package/src/cluster/spread-on-churn.ts +34 -54
- package/src/cohort-topic/host.ts +8 -6
- package/src/cohort-topic/membership-source.ts +1 -1
- package/src/cohort-topic/peer-codec.ts +34 -31
- package/src/cohort-topic/stream-util.ts +39 -4
- package/src/cohort-topic/topic-router.ts +12 -2
- package/src/dispute/client.ts +17 -7
- package/src/index.ts +64 -59
- package/src/libp2p-key-network.ts +1377 -1260
- package/src/libp2p-node-base.ts +186 -27
- package/src/libp2p-node-rn.ts +31 -30
- package/src/libp2p-node.ts +37 -36
- package/src/logger.ts +6 -1
- package/src/matchmaking/query-transport.ts +9 -9
- package/src/network/network-manager-service.ts +16 -5
- package/src/network/relay-reservation.ts +636 -0
- package/src/pend-validation.ts +3 -2
- package/src/protocol-client.ts +13 -1
- package/src/reactivity/forwarder-host.ts +2 -1
- package/src/reactivity/origination-manager.ts +3 -3
- package/src/reactivity/recover-transport.ts +39 -22
- package/src/reactivity/subscription-manager.ts +2 -2
- package/src/reactivity/topic-bytes.ts +35 -37
- package/src/repo/client.ts +172 -173
- package/src/repo/cluster-coordinator.ts +183 -25
- package/src/repo/coordinator-repo.ts +656 -506
- package/src/repo/i-under-replication-ledger.ts +89 -0
- package/src/repo/kv-under-replication-ledger.ts +302 -0
- package/src/repo/responsibility.ts +48 -0
- package/src/repo/service.ts +76 -39
- package/src/repo/stuck-reservation.ts +224 -0
- package/src/repo/under-replication-drain.ts +582 -0
- package/src/rn.ts +74 -69
- package/src/storage/block-latch.ts +7 -4
- package/src/storage/block-storage.ts +161 -10
- package/src/storage/i-block-storage.ts +60 -5
- package/src/storage/pending-claim.ts +200 -0
- package/src/storage/raw-store-codec.ts +26 -3
- package/src/storage/restoration-coordinator.ts +212 -211
- package/src/storage/ring-shift-coordinator.ts +271 -271
- package/src/storage/storage-repo.ts +280 -72
- package/src/storage/struct.ts +58 -0
- package/src/testing/mesh-harness.ts +293 -112
|
@@ -1,211 +1,212 @@
|
|
|
1
|
-
import type { BlockId } from '@optimystic/db-core';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
private readonly
|
|
31
|
-
private readonly
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
this.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this.metrics.successByRing.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
this.metrics.averageDurationMs
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
this.metrics.failureByRing.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
1
|
+
import type { BlockId } from '@optimystic/db-core';
|
|
2
|
+
import { routingKeyForBlock } from '@optimystic/db-core';
|
|
3
|
+
import { hashKey, type RingCoord } from 'p2p-fret';
|
|
4
|
+
import { peerIdFromString } from '@libp2p/peer-id';
|
|
5
|
+
import type { BlockArchive, RestoreCallback } from './struct.js';
|
|
6
|
+
import { SyncClient } from '../sync/client.js';
|
|
7
|
+
import type { IPeerNetwork } from '@optimystic/db-core';
|
|
8
|
+
import type { ArachnodeFretAdapter } from './arachnode-fret-adapter.js';
|
|
9
|
+
import { partitionCovers } from './arachnode-partition.js';
|
|
10
|
+
import { createLogger } from '../logger.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Coordinates block restoration across discovered Arachnode storage rings.
|
|
14
|
+
*
|
|
15
|
+
* Queries rings in order of broader coverage (inner rings first):
|
|
16
|
+
* 1. Transaction ring peers (my ring)
|
|
17
|
+
* 2. Inner storage rings (Ring N-1, N-2, ..., Ring 0)
|
|
18
|
+
*
|
|
19
|
+
* Each ring is discovered dynamically via FRET neighbor snapshots.
|
|
20
|
+
*/
|
|
21
|
+
export class RestorationCoordinator {
|
|
22
|
+
private readonly metrics = {
|
|
23
|
+
totalRequests: 0,
|
|
24
|
+
successByRing: new Map<number, number>(),
|
|
25
|
+
failureByRing: new Map<number, number>(),
|
|
26
|
+
averageDurationMs: 0
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
private readonly fretAdapter: ArachnodeFretAdapter,
|
|
31
|
+
private readonly peerNetwork: IPeerNetwork,
|
|
32
|
+
private readonly protocolPrefix: string,
|
|
33
|
+
/** Optional self peer id — used to skip dialing self on solo/bootstrap nodes. */
|
|
34
|
+
private readonly selfPeerId?: string
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
private readonly log = createLogger('storage:restoration')
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Restore a block by querying discovered storage rings.
|
|
41
|
+
*/
|
|
42
|
+
async restore(blockId: BlockId, rev?: number): Promise<BlockArchive | undefined> {
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
this.metrics.totalRequests++;
|
|
45
|
+
|
|
46
|
+
// Hash the block id once into the shared coordinate space. Peer responsibility
|
|
47
|
+
// (RingSelector.calculatePartition) and cohort assembly both operate on hashed
|
|
48
|
+
// coords, so restoration must filter in the same space — see getMyRingPeers and
|
|
49
|
+
// filterByPartition below, which reuse this value.
|
|
50
|
+
const blockCoord = await hashKey(routingKeyForBlock(blockId));
|
|
51
|
+
|
|
52
|
+
// 1. Try my transaction ring peers first
|
|
53
|
+
const myPeers = this.getMyRingPeers(blockCoord);
|
|
54
|
+
const myRingDepth = this.getMyRingDepth();
|
|
55
|
+
|
|
56
|
+
// Avoid dialing self: on a solo/bootstrap node with no listenAddrs, dialing self
|
|
57
|
+
// either hangs or fails noisily. Filter self out of the ring-peer list so the loop
|
|
58
|
+
// below can no-op cleanly when self is the only candidate.
|
|
59
|
+
const nonSelfMyPeers = this.selfPeerId
|
|
60
|
+
? myPeers.filter(p => p !== this.selfPeerId)
|
|
61
|
+
: myPeers;
|
|
62
|
+
if (nonSelfMyPeers.length === 0 && myRingDepth <= 0) {
|
|
63
|
+
this.log('restore:solo-node-skip blockId=%s', blockId);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const peerId of nonSelfMyPeers) {
|
|
68
|
+
const archive = await this.queryPeer(peerId, blockId, rev);
|
|
69
|
+
if (archive) {
|
|
70
|
+
this.recordSuccess(myRingDepth, blockId, Date.now() - startTime);
|
|
71
|
+
return archive;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// My transaction ring was queried and yielded nothing — count it as one ring failure.
|
|
75
|
+
this.recordFailure(myRingDepth);
|
|
76
|
+
|
|
77
|
+
// 2. Try inner storage rings (broader coverage)
|
|
78
|
+
for (let ringDepth = myRingDepth - 1; ringDepth >= 0; ringDepth--) {
|
|
79
|
+
const storagePeers = this.fretAdapter.findPeersAtRing(ringDepth);
|
|
80
|
+
|
|
81
|
+
// Filter to peers responsible for this block's partition (skip self — cannot dial self).
|
|
82
|
+
const responsiblePeers = this.filterByPartition(storagePeers, blockCoord, ringDepth)
|
|
83
|
+
.filter(p => !this.selfPeerId || p !== this.selfPeerId);
|
|
84
|
+
|
|
85
|
+
for (const peerIdStr of responsiblePeers) {
|
|
86
|
+
const archive = await this.queryPeer(peerIdStr, blockId, rev);
|
|
87
|
+
if (archive) {
|
|
88
|
+
this.recordSuccess(ringDepth, blockId, Date.now() - startTime);
|
|
89
|
+
return archive;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// This inner ring was queried and yielded nothing — count it as one ring failure.
|
|
93
|
+
this.recordFailure(ringDepth);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// No ring had the data
|
|
97
|
+
const duration = Date.now() - startTime;
|
|
98
|
+
this.log('restore failed for block %s after %dms', blockId, duration)
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create a RestoreCallback function that uses this coordinator.
|
|
104
|
+
*/
|
|
105
|
+
createRestoreCallback(): RestoreCallback {
|
|
106
|
+
return async (blockId: BlockId, rev?: number) => {
|
|
107
|
+
return await this.restore(blockId, rev);
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get peers in my transaction ring for a given block.
|
|
113
|
+
* @param blockCoord the block id already hashed into the shared coordinate space.
|
|
114
|
+
*/
|
|
115
|
+
private getMyRingPeers(blockCoord: RingCoord): string[] {
|
|
116
|
+
return this.fretAdapter.getFret().assembleCohort(blockCoord, 10);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get my own ring depth from Arachnode info.
|
|
121
|
+
*/
|
|
122
|
+
private getMyRingDepth(): number {
|
|
123
|
+
const myInfo = this.fretAdapter.getMyArachnodeInfo();
|
|
124
|
+
return myInfo?.ringDepth ?? 8; // Default to Ring 8
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Filter peers by partition responsibility.
|
|
129
|
+
* @param blockCoord the block id hashed into the shared coordinate space (same space
|
|
130
|
+
* RingSelector.calculatePartition uses for peer partitions).
|
|
131
|
+
*/
|
|
132
|
+
private filterByPartition(peers: string[], blockCoord: RingCoord, ringDepth: number): string[] {
|
|
133
|
+
if (ringDepth === 0) {
|
|
134
|
+
return peers; // Ring 0 covers all blocks
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return peers.filter(peerId => {
|
|
138
|
+
const info = this.fretAdapter.getArachnodeInfo(peerId);
|
|
139
|
+
if (!info || !info.partition) return false;
|
|
140
|
+
// Compare block prefix vs peer partition via the shared responsibility derivation.
|
|
141
|
+
return partitionCovers(info.partition, blockCoord);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Query a specific peer for a block.
|
|
147
|
+
*/
|
|
148
|
+
private async queryPeer(peerIdStr: string, blockId: BlockId, rev?: number): Promise<BlockArchive | undefined> {
|
|
149
|
+
try {
|
|
150
|
+
const peerId = peerIdFromString(peerIdStr);
|
|
151
|
+
const client = new SyncClient(
|
|
152
|
+
peerId,
|
|
153
|
+
this.peerNetwork,
|
|
154
|
+
this.protocolPrefix
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const response = await client.requestBlock({ blockId, rev });
|
|
158
|
+
return response.success ? response.archive : undefined;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
this.log('queryPeer failed for %s - %o', peerIdStr, error)
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Record successful restoration from a ring.
|
|
167
|
+
*/
|
|
168
|
+
private recordSuccess(ringDepth: number, blockId: BlockId, durationMs: number): void {
|
|
169
|
+
const count = this.metrics.successByRing.get(ringDepth) ?? 0;
|
|
170
|
+
this.metrics.successByRing.set(ringDepth, count + 1);
|
|
171
|
+
|
|
172
|
+
// Update rolling average duration
|
|
173
|
+
const totalSuccesses = Array.from(this.metrics.successByRing.values())
|
|
174
|
+
.reduce((sum, c) => sum + c, 0);
|
|
175
|
+
const prevTotal = this.metrics.averageDurationMs * (totalSuccesses - 1);
|
|
176
|
+
this.metrics.averageDurationMs = (prevTotal + durationMs) / totalSuccesses;
|
|
177
|
+
|
|
178
|
+
this.log('[Ring %d] Successfully restored block %s in %dms', ringDepth, blockId, durationMs);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Record that a ring was queried during a restore but did not yield the block.
|
|
183
|
+
* Counterpart to {@link recordSuccess}: the ring — not the individual peer query — is the
|
|
184
|
+
* failure unit, so this increments once per exhausted ring at the points where the peer
|
|
185
|
+
* loops in {@link restore} complete without returning an archive.
|
|
186
|
+
*/
|
|
187
|
+
private recordFailure(ringDepth: number): void {
|
|
188
|
+
const count = this.metrics.failureByRing.get(ringDepth) ?? 0;
|
|
189
|
+
this.metrics.failureByRing.set(ringDepth, count + 1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get restoration metrics for monitoring.
|
|
194
|
+
*/
|
|
195
|
+
getMetrics(): {
|
|
196
|
+
totalRequests: number;
|
|
197
|
+
successByRing: Map<number, number>;
|
|
198
|
+
failureByRing: Map<number, number>;
|
|
199
|
+
averageDurationMs: number;
|
|
200
|
+
} {
|
|
201
|
+
// Copy the Maps: a bare `{ ...this.metrics }` spreads only the top level, handing the
|
|
202
|
+
// caller the SAME Map instances this coordinator keeps mutating — the snapshot would
|
|
203
|
+
// then change under the caller's feet, and a caller mutation would corrupt internal state.
|
|
204
|
+
return {
|
|
205
|
+
totalRequests: this.metrics.totalRequests,
|
|
206
|
+
successByRing: new Map(this.metrics.successByRing),
|
|
207
|
+
failureByRing: new Map(this.metrics.failureByRing),
|
|
208
|
+
averageDurationMs: this.metrics.averageDurationMs
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|