@distrohelena/canton-explorer 0.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/.env.example +9 -0
- package/LICENSE +184 -0
- package/README.md +63 -0
- package/bin/canton-explorer.js +68 -0
- package/config/nodes.example.json +35 -0
- package/dist/public/assets/index-NfJYgVwb.css +1 -0
- package/dist/public/assets/index-ybPCCjei.js +1 -0
- package/dist/public/cantonexplorer.png +0 -0
- package/dist/public/favicon.svg +1 -0
- package/dist/public/icons.svg +24 -0
- package/dist/public/index.html +14 -0
- package/dist/scripts/list-local-parties.d.ts +1 -0
- package/dist/scripts/list-local-parties.js +64 -0
- package/dist/scripts/list-local-parties.js.map +1 -0
- package/dist/src/api/nodes.controller.d.ts +181 -0
- package/dist/src/api/nodes.controller.js +873 -0
- package/dist/src/api/nodes.controller.js.map +1 -0
- package/dist/src/app-bootstrap.d.ts +22 -0
- package/dist/src/app-bootstrap.js +52 -0
- package/dist/src/app-bootstrap.js.map +1 -0
- package/dist/src/app.module.d.ts +2 -0
- package/dist/src/app.module.js +48 -0
- package/dist/src/app.module.js.map +1 -0
- package/dist/src/cache/node-cache.service.d.ts +54 -0
- package/dist/src/cache/node-cache.service.js +154 -0
- package/dist/src/cache/node-cache.service.js.map +1 -0
- package/dist/src/config/node-config.schema.d.ts +100 -0
- package/dist/src/config/node-config.schema.js +83 -0
- package/dist/src/config/node-config.schema.js.map +1 -0
- package/dist/src/config/node-config.service.d.ts +7 -0
- package/dist/src/config/node-config.service.js +36 -0
- package/dist/src/config/node-config.service.js.map +1 -0
- package/dist/src/domain/node-health.d.ts +9 -0
- package/dist/src/domain/node-health.js +16 -0
- package/dist/src/domain/node-health.js.map +1 -0
- package/dist/src/domain/node.types.d.ts +563 -0
- package/dist/src/domain/node.types.js +3 -0
- package/dist/src/domain/node.types.js.map +1 -0
- package/dist/src/grpc/grpc-client.factory.d.ts +297 -0
- package/dist/src/grpc/grpc-client.factory.js +67 -0
- package/dist/src/grpc/grpc-client.factory.js.map +1 -0
- package/dist/src/grpc/grpc-error.util.d.ts +7 -0
- package/dist/src/grpc/grpc-error.util.js +31 -0
- package/dist/src/grpc/grpc-error.util.js.map +1 -0
- package/dist/src/grpc/grpc-operations.service.d.ts +96 -0
- package/dist/src/grpc/grpc-operations.service.js +844 -0
- package/dist/src/grpc/grpc-operations.service.js.map +1 -0
- package/dist/src/grpc/shared-secret-jwt.d.ts +6 -0
- package/dist/src/grpc/shared-secret-jwt.js +22 -0
- package/dist/src/grpc/shared-secret-jwt.js.map +1 -0
- package/dist/src/main.d.ts +1 -0
- package/dist/src/main.js +6 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/namespaces/namespace-fingerprint.service.d.ts +22 -0
- package/dist/src/namespaces/namespace-fingerprint.service.js +125 -0
- package/dist/src/namespaces/namespace-fingerprint.service.js.map +1 -0
- package/dist/src/orchestrator/node-poller.service.d.ts +26 -0
- package/dist/src/orchestrator/node-poller.service.js +224 -0
- package/dist/src/orchestrator/node-poller.service.js.map +1 -0
- package/dist/src/packages/daml-decoder.types.d.ts +69 -0
- package/dist/src/packages/daml-decoder.types.js +3 -0
- package/dist/src/packages/daml-decoder.types.js.map +1 -0
- package/dist/src/packages/daml-lf-archive-v2.descriptor.pb +0 -0
- package/dist/src/packages/daml-lf-archive.descriptor.pb +0 -0
- package/dist/src/packages/daml-lf-loader.d.ts +3 -0
- package/dist/src/packages/daml-lf-loader.js +51 -0
- package/dist/src/packages/daml-lf-loader.js.map +1 -0
- package/dist/src/packages/daml-lf-raw.util.d.ts +12 -0
- package/dist/src/packages/daml-lf-raw.util.js +117 -0
- package/dist/src/packages/daml-lf-raw.util.js.map +1 -0
- package/dist/src/packages/daml-lf-value.descriptor.pb +0 -0
- package/dist/src/packages/daml-value-decoder.service.d.ts +39 -0
- package/dist/src/packages/daml-value-decoder.service.js +463 -0
- package/dist/src/packages/daml-value-decoder.service.js.map +1 -0
- package/dist/src/packages/package-cache.service.d.ts +53 -0
- package/dist/src/packages/package-cache.service.js +288 -0
- package/dist/src/packages/package-cache.service.js.map +1 -0
- package/dist/src/packages/package-registry.service.d.ts +44 -0
- package/dist/src/packages/package-registry.service.js +625 -0
- package/dist/src/packages/package-registry.service.js.map +1 -0
- package/dist/src/packages/package-sync.service.d.ts +22 -0
- package/dist/src/packages/package-sync.service.js +129 -0
- package/dist/src/packages/package-sync.service.js.map +1 -0
- package/dist/src/packages/pqs-package.service.d.ts +9 -0
- package/dist/src/packages/pqs-package.service.js +118 -0
- package/dist/src/packages/pqs-package.service.js.map +1 -0
- package/dist/src/pqs/pqs-client.factory.d.ts +7 -0
- package/dist/src/pqs/pqs-client.factory.js +37 -0
- package/dist/src/pqs/pqs-client.factory.js.map +1 -0
- package/dist/src/pqs/pqs-summary.service.d.ts +229 -0
- package/dist/src/pqs/pqs-summary.service.js +4652 -0
- package/dist/src/pqs/pqs-summary.service.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.GrpcOperationsService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const node_config_schema_1 = require("../config/node-config.schema");
|
|
18
|
+
const node_config_service_1 = require("../config/node-config.service");
|
|
19
|
+
const grpc_client_factory_1 = require("./grpc-client.factory");
|
|
20
|
+
const HOLDING_V2_INTERFACE_ID = '#splice-api-token-holding-v2:Splice.Api.Token.HoldingV2:Holding';
|
|
21
|
+
const HOLDING_V2_INTERFACE_MODULE = 'Splice.Api.Token.HoldingV2';
|
|
22
|
+
const HOLDING_V2_INTERFACE_ENTITY = 'Holding';
|
|
23
|
+
const HOLDING_V2_PAGE_SIZE = 500;
|
|
24
|
+
let GrpcOperationsService = class GrpcOperationsService {
|
|
25
|
+
clientFactory;
|
|
26
|
+
nodeConfigService;
|
|
27
|
+
topologySdkPromise;
|
|
28
|
+
constructor(clientFactory, nodeConfigService) {
|
|
29
|
+
this.clientFactory = clientFactory;
|
|
30
|
+
this.nodeConfigService = nodeConfigService;
|
|
31
|
+
}
|
|
32
|
+
async fetchOperationalInfo(node) {
|
|
33
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
34
|
+
return {
|
|
35
|
+
target: null,
|
|
36
|
+
reachable: false,
|
|
37
|
+
healthCheckImplemented: false,
|
|
38
|
+
servingStatus: null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return this.withClient(node, async (client) => {
|
|
42
|
+
const response = await client.healthService.checkAsync({ service: '' });
|
|
43
|
+
const servingStatus = this.mapHealthStatus(response?.status);
|
|
44
|
+
return {
|
|
45
|
+
target: node.grpc.ledgerTarget,
|
|
46
|
+
reachable: true,
|
|
47
|
+
healthCheckImplemented: servingStatus !== null,
|
|
48
|
+
servingStatus,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async listLocalParties(node) {
|
|
53
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
return this.withClient(node, async (client) => this.listLocalPartiesWithClient(client));
|
|
57
|
+
}
|
|
58
|
+
async listKnownPartyFingerprints(node) {
|
|
59
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return this.withClient(node, async (client) => {
|
|
63
|
+
const [partyTopologyResponse, localParties] = await Promise.all([
|
|
64
|
+
client.topologyAggregationService.listPartiesAsync({
|
|
65
|
+
synchronizerIds: [],
|
|
66
|
+
}),
|
|
67
|
+
this.listLocalPartiesWithClient(client),
|
|
68
|
+
]);
|
|
69
|
+
const parties = this.uniqueNonEmptyStrings([
|
|
70
|
+
...(partyTopologyResponse.results ?? []).map((result) => result.party),
|
|
71
|
+
...localParties,
|
|
72
|
+
]);
|
|
73
|
+
return parties
|
|
74
|
+
.map((partyId) => this.extractPartyFingerprint(partyId))
|
|
75
|
+
.filter((fingerprint) => fingerprint !== null)
|
|
76
|
+
.sort((left, right) => left.localeCompare(right));
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async fetchHoldingV2Tokens(node) {
|
|
80
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
return this.withClient(node, async (client) => {
|
|
84
|
+
const activeContracts = await this.fetchHoldingV2ActiveContracts(client);
|
|
85
|
+
const deduped = new Map();
|
|
86
|
+
for (const contract of activeContracts) {
|
|
87
|
+
const token = this.extractHoldingV2TokenSummary(contract);
|
|
88
|
+
if (token && !deduped.has(token.tokenId)) {
|
|
89
|
+
deduped.set(token.tokenId, token);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return Array.from(deduped.values()).sort((left, right) => left.name.localeCompare(right.name) || left.tokenId.localeCompare(right.tokenId));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async fetchHoldingV2TokenHolders(node) {
|
|
96
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
return this.withClient(node, async (client) => {
|
|
100
|
+
const activeContracts = await this.fetchHoldingV2ActiveContracts(client);
|
|
101
|
+
const deduped = new Map();
|
|
102
|
+
for (const contract of activeContracts) {
|
|
103
|
+
const holder = this.extractHoldingV2TokenHolder(node, contract);
|
|
104
|
+
if (!holder) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const dedupeKey = holder.contractId ?? `${holder.tokenId}\u0000${holder.partyId}\u0000${holder.amount ?? ''}`;
|
|
108
|
+
if (!deduped.has(dedupeKey)) {
|
|
109
|
+
deduped.set(dedupeKey, holder);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return Array.from(deduped.values());
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async fetchPartyTopology(node, partyId) {
|
|
116
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
117
|
+
return {
|
|
118
|
+
nodeId: node.id,
|
|
119
|
+
label: node.label,
|
|
120
|
+
status: 'grpc_not_configured',
|
|
121
|
+
errorMessage: null,
|
|
122
|
+
isLocalParty: null,
|
|
123
|
+
partyToParticipants: [],
|
|
124
|
+
partyToKeyMappings: [],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
return await this.withClient(node, async (client) => {
|
|
129
|
+
const [partyTopologyResponse, keyOwnerResponse, rawPartyToParticipantResponse] = await Promise.all([
|
|
130
|
+
client.topologyAggregationService.listPartiesAsync({
|
|
131
|
+
filterParty: partyId,
|
|
132
|
+
synchronizerIds: [],
|
|
133
|
+
}),
|
|
134
|
+
client.topologyAggregationService.listKeyOwnersAsync({
|
|
135
|
+
filterKeyOwnerUid: partyId,
|
|
136
|
+
synchronizerIds: [],
|
|
137
|
+
}),
|
|
138
|
+
this.tryListRawPartyToParticipant(client, partyId),
|
|
139
|
+
]);
|
|
140
|
+
const aggregatedParticipantMappings = (partyTopologyResponse.results ?? [])
|
|
141
|
+
.filter((result) => result.party === partyId)
|
|
142
|
+
.flatMap((result) => (result.participants ?? []).map((participant) => ({
|
|
143
|
+
participantId: this.extractParticipantId(participant.participantUid),
|
|
144
|
+
participantUid: this.nullIfEmptyString(participant.participantUid),
|
|
145
|
+
permission: this.joinDistinctValues((participant.synchronizers ?? []).map((synchronizer) => synchronizer.permission)),
|
|
146
|
+
threshold: null,
|
|
147
|
+
synchronizerIds: this.uniqueNonEmptyStrings((participant.synchronizers ?? []).map((synchronizer) => synchronizer.synchronizerId ?? synchronizer.physicalSynchronizerId)),
|
|
148
|
+
})));
|
|
149
|
+
const rawPartyMappings = (rawPartyToParticipantResponse?.results ?? [])
|
|
150
|
+
.map((result) => result.item)
|
|
151
|
+
.filter((item) => item !== undefined && item !== null)
|
|
152
|
+
.filter((item) => item.party === partyId);
|
|
153
|
+
const rawTopologySynchronizerId = this.extractRawTopologySynchronizerId(rawPartyToParticipantResponse?.storeId);
|
|
154
|
+
const rawParticipantMappings = rawPartyMappings.flatMap((item) => (item.participants ?? []).map((participant) => ({
|
|
155
|
+
participantId: this.extractParticipantId(participant.participantUid),
|
|
156
|
+
participantUid: this.nullIfEmptyString(participant.participantUid),
|
|
157
|
+
permission: this.nullIfEmptyString(participant.permission),
|
|
158
|
+
threshold: typeof item.threshold === 'number' && Number.isFinite(item.threshold)
|
|
159
|
+
? item.threshold
|
|
160
|
+
: null,
|
|
161
|
+
synchronizerIds: rawTopologySynchronizerId ? [rawTopologySynchronizerId] : [],
|
|
162
|
+
})));
|
|
163
|
+
const aggregatedKeyMappings = (keyOwnerResponse.results ?? [])
|
|
164
|
+
.filter((result) => result.keyOwner === partyId)
|
|
165
|
+
.flatMap((result) => [
|
|
166
|
+
...(result.signingKeys ?? []).map((signingKey) => ({
|
|
167
|
+
keyFingerprint: this.nullIfEmptyString(signingKey.fingerprint)
|
|
168
|
+
?? this.computePublicKeyFingerprint(client, signingKey.publicKey, signingKey.format),
|
|
169
|
+
publicKey: this.bytesToHex(signingKey.publicKey),
|
|
170
|
+
purpose: this.joinDistinctValues(signingKey.usage ?? []),
|
|
171
|
+
keyType: this.nullIfEmptyString(signingKey.scheme),
|
|
172
|
+
keyFormat: this.nullIfEmptyString(signingKey.format),
|
|
173
|
+
keySpec: this.nullIfEmptyString(signingKey.keySpec),
|
|
174
|
+
threshold: null,
|
|
175
|
+
synchronizerIds: this.uniqueNonEmptyStrings([
|
|
176
|
+
result.synchronizerId ?? result.physicalSynchronizerId,
|
|
177
|
+
]),
|
|
178
|
+
})),
|
|
179
|
+
...(result.encryptionKeys ?? []).map((encryptionKey) => ({
|
|
180
|
+
keyFingerprint: this.nullIfEmptyString(encryptionKey.fingerprint)
|
|
181
|
+
?? this.computePublicKeyFingerprint(client, encryptionKey.publicKey, encryptionKey.format),
|
|
182
|
+
publicKey: this.bytesToHex(encryptionKey.publicKey),
|
|
183
|
+
purpose: 'encryption',
|
|
184
|
+
keyType: this.nullIfEmptyString(encryptionKey.scheme),
|
|
185
|
+
keyFormat: this.nullIfEmptyString(encryptionKey.format),
|
|
186
|
+
keySpec: this.nullIfEmptyString(encryptionKey.keySpec),
|
|
187
|
+
threshold: null,
|
|
188
|
+
synchronizerIds: this.uniqueNonEmptyStrings([
|
|
189
|
+
result.synchronizerId ?? result.physicalSynchronizerId,
|
|
190
|
+
]),
|
|
191
|
+
})),
|
|
192
|
+
]);
|
|
193
|
+
const rawSigningKeyMappings = rawPartyMappings.flatMap((item) => (item.partySigningKeys?.keys ?? []).map((signingKey) => ({
|
|
194
|
+
keyFingerprint: this.computePublicKeyFingerprint(client, signingKey.publicKey, signingKey.format),
|
|
195
|
+
publicKey: this.bytesToHex(signingKey.publicKey),
|
|
196
|
+
purpose: this.joinDistinctValues(signingKey.usage ?? []),
|
|
197
|
+
keyType: this.nullIfEmptyString(signingKey.scheme),
|
|
198
|
+
keyFormat: this.nullIfEmptyString(signingKey.format),
|
|
199
|
+
keySpec: this.nullIfEmptyString(signingKey.keySpec),
|
|
200
|
+
threshold: typeof item.partySigningKeys?.threshold === 'number'
|
|
201
|
+
&& Number.isFinite(item.partySigningKeys.threshold)
|
|
202
|
+
? item.partySigningKeys.threshold
|
|
203
|
+
: null,
|
|
204
|
+
synchronizerIds: rawTopologySynchronizerId ? [rawTopologySynchronizerId] : [],
|
|
205
|
+
})));
|
|
206
|
+
return {
|
|
207
|
+
nodeId: node.id,
|
|
208
|
+
label: node.label,
|
|
209
|
+
status: 'ok',
|
|
210
|
+
errorMessage: null,
|
|
211
|
+
isLocalParty: null,
|
|
212
|
+
partyToParticipants: this.mergePartyTopologyParticipants([
|
|
213
|
+
...aggregatedParticipantMappings,
|
|
214
|
+
...rawParticipantMappings,
|
|
215
|
+
]),
|
|
216
|
+
partyToKeyMappings: this.mergePartyTopologyKeyMappings([
|
|
217
|
+
...aggregatedKeyMappings,
|
|
218
|
+
...rawSigningKeyMappings,
|
|
219
|
+
]),
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
return {
|
|
225
|
+
nodeId: node.id,
|
|
226
|
+
label: node.label,
|
|
227
|
+
status: 'grpc_error',
|
|
228
|
+
errorMessage: error instanceof Error ? error.message : 'Unknown gRPC error',
|
|
229
|
+
isLocalParty: null,
|
|
230
|
+
partyToParticipants: [],
|
|
231
|
+
partyToKeyMappings: [],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async fetchParticipantStatus(node) {
|
|
236
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
237
|
+
throw new Error(`Node ${node.id} does not define grpc settings`);
|
|
238
|
+
}
|
|
239
|
+
return this.withClient(node, async (client) => {
|
|
240
|
+
const response = await client.participantStatusService.getParticipantStatusAsync({});
|
|
241
|
+
const status = response.status;
|
|
242
|
+
if (status) {
|
|
243
|
+
return {
|
|
244
|
+
participantStatus: {
|
|
245
|
+
uid: this.nullIfEmptyString(status.uid),
|
|
246
|
+
uptime: this.formatDuration(status.uptime),
|
|
247
|
+
ports: status.ports ?? {},
|
|
248
|
+
active: status.active,
|
|
249
|
+
commonStatusActive: typeof status.active === 'boolean' ? status.active : null,
|
|
250
|
+
version: this.nullIfEmptyString(status.version),
|
|
251
|
+
supportedProtocolVersions: status.supportedProtocolVersions ?? [],
|
|
252
|
+
topologyQueues: status.topologyQueues
|
|
253
|
+
? {
|
|
254
|
+
manager: status.topologyQueues.manager,
|
|
255
|
+
dispatcher: status.topologyQueues.dispatcher,
|
|
256
|
+
clients: status.topologyQueues.clients,
|
|
257
|
+
}
|
|
258
|
+
: null,
|
|
259
|
+
components: (status.components ?? []).map((component) => this.mapComponentStatus(component)),
|
|
260
|
+
connectedSynchronizers: (status.connectedSynchronizers ?? []).map((synchronizer) => ({
|
|
261
|
+
physicalSynchronizerId: this.nullIfEmptyString(synchronizer.physicalSynchronizerId),
|
|
262
|
+
health: this.mapSynchronizerHealth(synchronizer.health),
|
|
263
|
+
})),
|
|
264
|
+
},
|
|
265
|
+
notInitialized: null,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (response.notInitialized) {
|
|
269
|
+
return {
|
|
270
|
+
participantStatus: null,
|
|
271
|
+
notInitialized: {
|
|
272
|
+
active: response.notInitialized.active,
|
|
273
|
+
waitingForExternalInput: this.mapWaitingForExternalInput(response.notInitialized.waitingForExternalInput),
|
|
274
|
+
version: this.nullIfEmptyString(response.notInitialized.version),
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
participantStatus: null,
|
|
280
|
+
notInitialized: {
|
|
281
|
+
active: false,
|
|
282
|
+
waitingForExternalInput: 'unspecified',
|
|
283
|
+
version: null,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
async fetchPackageRefs(node) {
|
|
289
|
+
if (node.mode !== 'pqs_with_grpc') {
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
return this.withClient(node, async (client) => {
|
|
293
|
+
try {
|
|
294
|
+
const response = await client.participantPackageService.listPackagesAsync({});
|
|
295
|
+
return (response.packageDescriptions ?? [])
|
|
296
|
+
.map((description) => ({
|
|
297
|
+
packageId: description.packageId,
|
|
298
|
+
mainPackageId: description.packageId,
|
|
299
|
+
name: description.name || null,
|
|
300
|
+
version: description.version || null,
|
|
301
|
+
uploadedAt: description.uploadedAt?.toISOString() ?? null,
|
|
302
|
+
packageSize: description.size ?? null,
|
|
303
|
+
}))
|
|
304
|
+
.sort((left, right) => left.packageId.localeCompare(right.packageId));
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
if (!this.shouldFallbackToLedgerPackageListing(error)) {
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const fallbackResponse = await client.packageService.listPackagesAsync({});
|
|
312
|
+
const packageRefs = await Promise.all((fallbackResponse.packageIds ?? []).map(async (packageId) => {
|
|
313
|
+
const packageResponse = await client.packageService.getPackageAsync({ packageId });
|
|
314
|
+
const archivePayload = Buffer.from(packageResponse.archivePayload);
|
|
315
|
+
const metadata = await this.decodePackageArchiveMetadata(archivePayload);
|
|
316
|
+
return {
|
|
317
|
+
packageId,
|
|
318
|
+
mainPackageId: packageId,
|
|
319
|
+
name: metadata.name,
|
|
320
|
+
version: metadata.version,
|
|
321
|
+
uploadedAt: null,
|
|
322
|
+
packageSize: archivePayload.length,
|
|
323
|
+
};
|
|
324
|
+
}));
|
|
325
|
+
return packageRefs.sort((left, right) => left.packageId.localeCompare(right.packageId));
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
async fetchPackagesByRefs(node, packageRefs) {
|
|
329
|
+
if (node.mode !== 'pqs_with_grpc' || packageRefs.length === 0) {
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
332
|
+
return this.withClient(node, async (client) => {
|
|
333
|
+
return Promise.all(packageRefs.map(async (packageRef) => {
|
|
334
|
+
const response = await client.packageService.getPackageAsync({
|
|
335
|
+
packageId: packageRef.packageId,
|
|
336
|
+
});
|
|
337
|
+
return {
|
|
338
|
+
packageId: packageRef.packageId,
|
|
339
|
+
name: packageRef.name,
|
|
340
|
+
version: packageRef.version,
|
|
341
|
+
uploadedAt: packageRef.uploadedAt,
|
|
342
|
+
packageSize: packageRef.packageSize,
|
|
343
|
+
data: Buffer.from(response.archivePayload),
|
|
344
|
+
};
|
|
345
|
+
}));
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
mapHealthStatus(status) {
|
|
349
|
+
switch (status) {
|
|
350
|
+
case 'serving':
|
|
351
|
+
return 'SERVING';
|
|
352
|
+
case 'notServing':
|
|
353
|
+
return 'NOT_SERVING';
|
|
354
|
+
case 'serviceUnknown':
|
|
355
|
+
return 'SERVICE_UNKNOWN';
|
|
356
|
+
case 'unknown':
|
|
357
|
+
return 'UNKNOWN';
|
|
358
|
+
default:
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
shouldFallbackToLedgerPackageListing(error) {
|
|
363
|
+
if (!(error instanceof Error)) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
return error.message.includes('Method not found:') && error.message.includes('PackageService/ListPackages');
|
|
367
|
+
}
|
|
368
|
+
loadTopologySdk() {
|
|
369
|
+
this.topologySdkPromise ??= (() => {
|
|
370
|
+
const sdkModulePath = '@distrohelena/canton-typescript-sdk';
|
|
371
|
+
return import(sdkModulePath);
|
|
372
|
+
})();
|
|
373
|
+
return this.topologySdkPromise;
|
|
374
|
+
}
|
|
375
|
+
buildTopologyStoreId(sdk, store) {
|
|
376
|
+
switch (store.kind) {
|
|
377
|
+
case 'authorized':
|
|
378
|
+
return new sdk.TopologyStoreId({
|
|
379
|
+
kind: sdk.TopologyStoreKind.authorized,
|
|
380
|
+
authorized: new sdk.TopologyStoreAuthorized(),
|
|
381
|
+
});
|
|
382
|
+
case 'synchronizer':
|
|
383
|
+
return new sdk.TopologyStoreId({
|
|
384
|
+
kind: sdk.TopologyStoreKind.synchronizer,
|
|
385
|
+
synchronizer: new sdk.TopologyStoreSynchronizer({
|
|
386
|
+
id: store.synchronizer?.id,
|
|
387
|
+
physicalId: store.synchronizer?.physicalId,
|
|
388
|
+
}),
|
|
389
|
+
});
|
|
390
|
+
case 'temporary':
|
|
391
|
+
if (!store.temporary?.name) {
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
return new sdk.TopologyStoreId({
|
|
395
|
+
kind: sdk.TopologyStoreKind.temporary,
|
|
396
|
+
temporary: new sdk.TopologyStoreTemporary({
|
|
397
|
+
name: store.temporary.name,
|
|
398
|
+
}),
|
|
399
|
+
});
|
|
400
|
+
default:
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async fetchHoldingV2ActiveContracts(client) {
|
|
405
|
+
const localParties = await this.listLocalPartiesWithClient(client);
|
|
406
|
+
const contracts = [];
|
|
407
|
+
for (const partyId of localParties) {
|
|
408
|
+
let nextPageToken;
|
|
409
|
+
do {
|
|
410
|
+
const response = await client.stateService.getActiveContractsPageAsync({
|
|
411
|
+
party: partyId,
|
|
412
|
+
interfaceId: HOLDING_V2_INTERFACE_ID,
|
|
413
|
+
includeInterfaceView: true,
|
|
414
|
+
maxPageSize: HOLDING_V2_PAGE_SIZE,
|
|
415
|
+
pageToken: nextPageToken,
|
|
416
|
+
});
|
|
417
|
+
contracts.push(...(response.contracts ?? []));
|
|
418
|
+
nextPageToken =
|
|
419
|
+
response.nextPageToken && response.nextPageToken.length > 0
|
|
420
|
+
? response.nextPageToken
|
|
421
|
+
: undefined;
|
|
422
|
+
} while (nextPageToken);
|
|
423
|
+
}
|
|
424
|
+
return contracts;
|
|
425
|
+
}
|
|
426
|
+
extractHoldingV2TokenSummary(contract) {
|
|
427
|
+
const view = this.findHoldingV2View(contract);
|
|
428
|
+
if (!view) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
const issuer = this.readLedgerNestedScalarField(view, ['instrumentId', 'admin']);
|
|
432
|
+
const intrinsicId = this.readLedgerNestedScalarField(view, ['instrumentId', 'id']);
|
|
433
|
+
if (!issuer || !intrinsicId) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
const name = this.readConfiguredLedgerTokenMetadata(view, 'name') ?? intrinsicId;
|
|
437
|
+
const symbol = this.readConfiguredLedgerTokenMetadata(view, 'symbol');
|
|
438
|
+
return {
|
|
439
|
+
tokenId: `${issuer}::${intrinsicId}`,
|
|
440
|
+
name,
|
|
441
|
+
symbol,
|
|
442
|
+
issuer,
|
|
443
|
+
source: 'grpc',
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
extractHoldingV2TokenHolder(node, contract) {
|
|
447
|
+
const view = this.findHoldingV2View(contract);
|
|
448
|
+
if (!view) {
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
const issuer = this.readLedgerNestedScalarField(view, ['instrumentId', 'admin']);
|
|
452
|
+
const intrinsicId = this.readLedgerNestedScalarField(view, ['instrumentId', 'id']);
|
|
453
|
+
const partyId = this.readLedgerNestedScalarField(view, ['account', 'owner']);
|
|
454
|
+
if (!issuer || !intrinsicId || !partyId) {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
contractId: this.nullIfEmptyString(contract.createdEvent?.contractId),
|
|
459
|
+
nodeId: node.id,
|
|
460
|
+
label: node.label,
|
|
461
|
+
tokenId: `${issuer}::${intrinsicId}`,
|
|
462
|
+
partyId,
|
|
463
|
+
amount: this.readLedgerScalarField(view, 'amount'),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
findHoldingV2View(contract) {
|
|
467
|
+
for (const interfaceView of contract.createdEvent?.interfaceViews ?? []) {
|
|
468
|
+
if (interfaceView.interfaceId?.moduleName !== HOLDING_V2_INTERFACE_MODULE
|
|
469
|
+
|| interfaceView.interfaceId?.entityName !== HOLDING_V2_INTERFACE_ENTITY) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if ((interfaceView.viewStatus?.code ?? 0) !== 0) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
return interfaceView.viewValue ?? null;
|
|
476
|
+
}
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
findLedgerField(record, label) {
|
|
480
|
+
return record?.fields?.find((field) => field.label === label)?.value;
|
|
481
|
+
}
|
|
482
|
+
isLedgerRecordValue(value) {
|
|
483
|
+
return (typeof value === 'object'
|
|
484
|
+
&& value !== null
|
|
485
|
+
&& 'sum' in value
|
|
486
|
+
&& typeof value.sum === 'object'
|
|
487
|
+
&& value.sum?.oneofKind === 'record');
|
|
488
|
+
}
|
|
489
|
+
readLedgerScalar(value) {
|
|
490
|
+
if (!value || typeof value !== 'object' || !('sum' in value)) {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
const sum = value.sum;
|
|
494
|
+
switch (sum?.oneofKind) {
|
|
495
|
+
case 'party':
|
|
496
|
+
return this.nullIfEmptyString(sum.party);
|
|
497
|
+
case 'text':
|
|
498
|
+
return this.nullIfEmptyString(sum.text);
|
|
499
|
+
case 'numeric':
|
|
500
|
+
return this.nullIfEmptyString(sum.numeric);
|
|
501
|
+
case 'int64':
|
|
502
|
+
return this.nullIfEmptyString(sum.int64);
|
|
503
|
+
case 'contractId':
|
|
504
|
+
return this.nullIfEmptyString(sum.contractId);
|
|
505
|
+
case 'bool':
|
|
506
|
+
return typeof sum.bool === 'boolean' ? String(sum.bool) : null;
|
|
507
|
+
case 'optional':
|
|
508
|
+
return this.readLedgerScalar(sum.optional?.value);
|
|
509
|
+
case 'enum':
|
|
510
|
+
return this.nullIfEmptyString(sum.enum?.constructor);
|
|
511
|
+
case 'variant':
|
|
512
|
+
return this.nullIfEmptyString(sum.variant?.constructor);
|
|
513
|
+
default:
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
readLedgerScalarField(record, label) {
|
|
518
|
+
return this.readLedgerScalar(this.findLedgerField(record, label));
|
|
519
|
+
}
|
|
520
|
+
readLedgerNestedScalarField(record, path) {
|
|
521
|
+
return this.readLedgerScalar(this.getLedgerFieldValueAtPath(record, path));
|
|
522
|
+
}
|
|
523
|
+
readLedgerTextMapEntryField(record, path, entryKey) {
|
|
524
|
+
const targetValue = this.getLedgerFieldValueAtPath(record, path);
|
|
525
|
+
if (!targetValue || typeof targetValue !== 'object' || !('sum' in targetValue)) {
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
const textMapEntries = targetValue.sum;
|
|
529
|
+
if (textMapEntries?.oneofKind !== 'textMap') {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
const matchingEntry = textMapEntries.textMap?.entries?.find((entry) => entry.key === entryKey);
|
|
533
|
+
return this.readLedgerScalar(matchingEntry?.value);
|
|
534
|
+
}
|
|
535
|
+
readConfiguredLedgerTokenMetadata(record, field) {
|
|
536
|
+
const keys = this.getTokenMetadataConfig()[field === 'name' ? 'nameKeys' : 'symbolKeys'];
|
|
537
|
+
for (const key of keys) {
|
|
538
|
+
const value = this.readLedgerTextMapEntryField(record, ['meta', 'values'], key);
|
|
539
|
+
if (value) {
|
|
540
|
+
return value;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
getTokenMetadataConfig() {
|
|
546
|
+
return this.nodeConfigService?.getTokenMetadataConfig() ?? {
|
|
547
|
+
nameKeys: [...node_config_schema_1.DEFAULT_TOKEN_METADATA_CONFIG.nameKeys],
|
|
548
|
+
symbolKeys: [...node_config_schema_1.DEFAULT_TOKEN_METADATA_CONFIG.symbolKeys],
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
getLedgerFieldValueAtPath(record, path) {
|
|
552
|
+
let currentRecord = record;
|
|
553
|
+
for (let index = 0; index < path.length; index += 1) {
|
|
554
|
+
const fieldValue = this.findLedgerField(currentRecord, path[index] ?? '');
|
|
555
|
+
if (fieldValue === undefined) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
if (index === path.length - 1) {
|
|
559
|
+
return fieldValue;
|
|
560
|
+
}
|
|
561
|
+
if (!this.isLedgerRecordValue(fieldValue)) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
currentRecord = fieldValue.sum?.record ?? null;
|
|
565
|
+
}
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
nullIfEmptyString(value) {
|
|
569
|
+
return typeof value === 'string' && value.trim().length > 0 ? value : null;
|
|
570
|
+
}
|
|
571
|
+
async tryListRawPartyToParticipant(client, partyId) {
|
|
572
|
+
if (!client.topologyManagerReadService?.listPartyToParticipantAsync
|
|
573
|
+
|| !client.topologyManagerReadService.listAvailableStoresAsync) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
try {
|
|
577
|
+
const sdk = await this.loadTopologySdk();
|
|
578
|
+
const availableStores = await client.topologyManagerReadService.listAvailableStoresAsync({});
|
|
579
|
+
const synchronizerStores = (availableStores.storeIds ?? []).filter((store) => store.kind === 'synchronizer' && store.synchronizer !== undefined);
|
|
580
|
+
for (const storeId of synchronizerStores) {
|
|
581
|
+
try {
|
|
582
|
+
const response = await client.topologyManagerReadService.listPartyToParticipantAsync(new sdk.ListPartyToParticipantRequest({
|
|
583
|
+
filterParty: partyId,
|
|
584
|
+
baseQuery: new sdk.TopologyBaseQuery({
|
|
585
|
+
storeId: this.buildTopologyStoreId(sdk, storeId),
|
|
586
|
+
headState: true,
|
|
587
|
+
}),
|
|
588
|
+
}));
|
|
589
|
+
if ((response.results ?? []).length > 0) {
|
|
590
|
+
return {
|
|
591
|
+
storeId,
|
|
592
|
+
results: response.results,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
catch {
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
uniqueNonEmptyStrings(values) {
|
|
607
|
+
return Array.from(new Set(values
|
|
608
|
+
.map((value) => this.nullIfEmptyString(value))
|
|
609
|
+
.filter((value) => value !== null)));
|
|
610
|
+
}
|
|
611
|
+
joinDistinctValues(values) {
|
|
612
|
+
const normalizedValues = this.uniqueNonEmptyStrings(values);
|
|
613
|
+
return normalizedValues.length > 0 ? normalizedValues.join(', ') : null;
|
|
614
|
+
}
|
|
615
|
+
mergePartyTopologyParticipants(mappings) {
|
|
616
|
+
const merged = new Map();
|
|
617
|
+
for (const mapping of mappings) {
|
|
618
|
+
const key = mapping.participantUid ?? mapping.participantId ?? JSON.stringify(mapping);
|
|
619
|
+
const existing = merged.get(key);
|
|
620
|
+
if (!existing) {
|
|
621
|
+
merged.set(key, {
|
|
622
|
+
participantId: mapping.participantId,
|
|
623
|
+
participantUid: mapping.participantUid,
|
|
624
|
+
permission: mapping.permission,
|
|
625
|
+
threshold: mapping.threshold,
|
|
626
|
+
synchronizerIds: [...mapping.synchronizerIds],
|
|
627
|
+
});
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
existing.participantId ??= mapping.participantId;
|
|
631
|
+
existing.participantUid ??= mapping.participantUid;
|
|
632
|
+
existing.permission ??= mapping.permission;
|
|
633
|
+
existing.threshold ??= mapping.threshold;
|
|
634
|
+
existing.synchronizerIds = this.uniqueNonEmptyStrings([
|
|
635
|
+
...existing.synchronizerIds,
|
|
636
|
+
...mapping.synchronizerIds,
|
|
637
|
+
]);
|
|
638
|
+
}
|
|
639
|
+
return Array.from(merged.values()).filter((mapping) => mapping.participantId !== null
|
|
640
|
+
|| mapping.participantUid !== null
|
|
641
|
+
|| mapping.permission !== null
|
|
642
|
+
|| mapping.threshold !== null
|
|
643
|
+
|| mapping.synchronizerIds.length > 0);
|
|
644
|
+
}
|
|
645
|
+
mergePartyTopologyKeyMappings(mappings) {
|
|
646
|
+
const merged = new Map();
|
|
647
|
+
for (const mapping of mappings) {
|
|
648
|
+
const key = mapping.keyFingerprint ?? JSON.stringify(mapping);
|
|
649
|
+
const existing = merged.get(key);
|
|
650
|
+
if (!existing) {
|
|
651
|
+
merged.set(key, {
|
|
652
|
+
keyFingerprint: mapping.keyFingerprint,
|
|
653
|
+
publicKey: mapping.publicKey,
|
|
654
|
+
purpose: mapping.purpose,
|
|
655
|
+
keyType: mapping.keyType,
|
|
656
|
+
keyFormat: mapping.keyFormat,
|
|
657
|
+
keySpec: mapping.keySpec,
|
|
658
|
+
threshold: mapping.threshold,
|
|
659
|
+
synchronizerIds: [...mapping.synchronizerIds],
|
|
660
|
+
});
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
existing.keyFingerprint ??= mapping.keyFingerprint;
|
|
664
|
+
existing.publicKey ??= mapping.publicKey;
|
|
665
|
+
existing.purpose ??= mapping.purpose;
|
|
666
|
+
existing.keyType ??= mapping.keyType;
|
|
667
|
+
existing.keyFormat ??= mapping.keyFormat;
|
|
668
|
+
existing.keySpec ??= mapping.keySpec;
|
|
669
|
+
existing.threshold ??= mapping.threshold;
|
|
670
|
+
existing.synchronizerIds = this.uniqueNonEmptyStrings([
|
|
671
|
+
...existing.synchronizerIds,
|
|
672
|
+
...mapping.synchronizerIds,
|
|
673
|
+
]);
|
|
674
|
+
}
|
|
675
|
+
return Array.from(merged.values()).filter((mapping) => mapping.keyFingerprint !== null
|
|
676
|
+
|| mapping.publicKey !== null
|
|
677
|
+
|| mapping.purpose !== null
|
|
678
|
+
|| mapping.keyType !== null
|
|
679
|
+
|| mapping.keyFormat !== null
|
|
680
|
+
|| mapping.keySpec !== null
|
|
681
|
+
|| mapping.threshold !== null
|
|
682
|
+
|| mapping.synchronizerIds.length > 0);
|
|
683
|
+
}
|
|
684
|
+
bytesToHex(value) {
|
|
685
|
+
if (!value || value.length === 0) {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
return Buffer.from(value).toString('hex');
|
|
689
|
+
}
|
|
690
|
+
computePublicKeyFingerprint(client, publicKey, format) {
|
|
691
|
+
if (!publicKey || publicKey.length === 0) {
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
return this.nullIfEmptyString(client.hashing?.computePublicKeyFingerprint(publicKey, this.nullIfEmptyString(format) ?? undefined));
|
|
695
|
+
}
|
|
696
|
+
extractParticipantId(participantUid) {
|
|
697
|
+
const normalizedParticipantUid = this.nullIfEmptyString(participantUid);
|
|
698
|
+
if (!normalizedParticipantUid) {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
const separatorIndex = normalizedParticipantUid.indexOf('::');
|
|
702
|
+
if (separatorIndex === -1) {
|
|
703
|
+
return normalizedParticipantUid;
|
|
704
|
+
}
|
|
705
|
+
return normalizedParticipantUid.slice(0, separatorIndex) || null;
|
|
706
|
+
}
|
|
707
|
+
async listLocalPartiesWithClient(client) {
|
|
708
|
+
const parties = [];
|
|
709
|
+
let nextPageToken;
|
|
710
|
+
do {
|
|
711
|
+
const response = await client.partyManagementService.listKnownPartiesAsync({
|
|
712
|
+
pageSize: 1000,
|
|
713
|
+
pageToken: nextPageToken,
|
|
714
|
+
});
|
|
715
|
+
for (const partyDetail of response.partyDetails ?? []) {
|
|
716
|
+
if (partyDetail.isLocal) {
|
|
717
|
+
parties.push(partyDetail.party);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
nextPageToken = response.nextPageToken;
|
|
721
|
+
} while (nextPageToken);
|
|
722
|
+
return parties.sort((left, right) => left.localeCompare(right));
|
|
723
|
+
}
|
|
724
|
+
extractPartyFingerprint(partyId) {
|
|
725
|
+
const normalizedPartyId = this.nullIfEmptyString(partyId);
|
|
726
|
+
if (!normalizedPartyId) {
|
|
727
|
+
return null;
|
|
728
|
+
}
|
|
729
|
+
const separatorIndex = normalizedPartyId.indexOf('::');
|
|
730
|
+
if (separatorIndex === -1) {
|
|
731
|
+
return normalizedPartyId;
|
|
732
|
+
}
|
|
733
|
+
const fingerprint = normalizedPartyId.slice(separatorIndex + 2).trim();
|
|
734
|
+
return fingerprint.length > 0 ? fingerprint : null;
|
|
735
|
+
}
|
|
736
|
+
extractRawTopologySynchronizerId(storeId) {
|
|
737
|
+
if (storeId?.kind !== 'synchronizer') {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
return this.nullIfEmptyString(storeId.synchronizer?.id ?? storeId.synchronizer?.physicalId);
|
|
741
|
+
}
|
|
742
|
+
formatDuration(duration) {
|
|
743
|
+
if (!duration) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
const seconds = duration.seconds === undefined || duration.seconds === null
|
|
747
|
+
? null
|
|
748
|
+
: typeof duration.seconds === 'bigint'
|
|
749
|
+
? duration.seconds.toString()
|
|
750
|
+
: String(duration.seconds);
|
|
751
|
+
const nanos = typeof duration.nanos === 'number' ? duration.nanos : 0;
|
|
752
|
+
if (seconds === null) {
|
|
753
|
+
return nanos > 0 ? `${nanos}ns` : null;
|
|
754
|
+
}
|
|
755
|
+
return nanos > 0 ? `${seconds}s ${nanos}ns` : `${seconds}s`;
|
|
756
|
+
}
|
|
757
|
+
mapComponentStatus(component) {
|
|
758
|
+
switch (component.kind) {
|
|
759
|
+
case 'ok':
|
|
760
|
+
return {
|
|
761
|
+
name: component.name,
|
|
762
|
+
severity: 'ok',
|
|
763
|
+
description: component.description ?? null,
|
|
764
|
+
};
|
|
765
|
+
case 'degraded':
|
|
766
|
+
return {
|
|
767
|
+
name: component.name,
|
|
768
|
+
severity: 'degraded',
|
|
769
|
+
description: component.description ?? null,
|
|
770
|
+
};
|
|
771
|
+
case 'failed':
|
|
772
|
+
return {
|
|
773
|
+
name: component.name,
|
|
774
|
+
severity: 'failed',
|
|
775
|
+
description: component.description ?? null,
|
|
776
|
+
};
|
|
777
|
+
case 'fatal':
|
|
778
|
+
return {
|
|
779
|
+
name: component.name,
|
|
780
|
+
severity: 'fatal',
|
|
781
|
+
description: component.description ?? null,
|
|
782
|
+
};
|
|
783
|
+
default:
|
|
784
|
+
return {
|
|
785
|
+
name: component.name,
|
|
786
|
+
severity: 'failed',
|
|
787
|
+
description: null,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
mapSynchronizerHealth(health) {
|
|
792
|
+
switch (health) {
|
|
793
|
+
case 'healthy':
|
|
794
|
+
case 1:
|
|
795
|
+
return 'healthy';
|
|
796
|
+
case 'unhealthy':
|
|
797
|
+
case 2:
|
|
798
|
+
return 'unhealthy';
|
|
799
|
+
case 'unspecified':
|
|
800
|
+
case 0:
|
|
801
|
+
return 'unspecified';
|
|
802
|
+
default:
|
|
803
|
+
return 'unspecified';
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
mapWaitingForExternalInput(value) {
|
|
807
|
+
switch (value) {
|
|
808
|
+
case 'id':
|
|
809
|
+
return 'id';
|
|
810
|
+
case 'nodeTopology':
|
|
811
|
+
return 'node_topology';
|
|
812
|
+
case 'initialization':
|
|
813
|
+
return 'initialization';
|
|
814
|
+
default:
|
|
815
|
+
return 'unspecified';
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
async decodePackageArchiveMetadata(archivePayload) {
|
|
819
|
+
const sdk = await import('@distrohelena/canton-typescript-sdk/daml-lf');
|
|
820
|
+
const packageLoader = new sdk.DamlLfPackageLoader();
|
|
821
|
+
const decodedPackage = packageLoader.loadPackageOrThrow(archivePayload);
|
|
822
|
+
return {
|
|
823
|
+
name: decodedPackage.packageName || null,
|
|
824
|
+
version: decodedPackage.packageVersion || null,
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
async withClient(node, run) {
|
|
828
|
+
const client = await this.clientFactory.create(node);
|
|
829
|
+
try {
|
|
830
|
+
return await run(client);
|
|
831
|
+
}
|
|
832
|
+
finally {
|
|
833
|
+
await client.disposeAsync?.();
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
exports.GrpcOperationsService = GrpcOperationsService;
|
|
838
|
+
exports.GrpcOperationsService = GrpcOperationsService = __decorate([
|
|
839
|
+
(0, common_1.Injectable)(),
|
|
840
|
+
__param(1, (0, common_1.Optional)()),
|
|
841
|
+
__metadata("design:paramtypes", [grpc_client_factory_1.GrpcClientFactory,
|
|
842
|
+
node_config_service_1.NodeConfigService])
|
|
843
|
+
], GrpcOperationsService);
|
|
844
|
+
//# sourceMappingURL=grpc-operations.service.js.map
|