@dignetwork/dig-sdk 0.0.1-alpha.5 → 0.0.1-alpha.51
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/DataIntegrityTree/DataIntegrityTree.d.ts +2 -2
- package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +1 -1
- package/dist/DataIntegrityTree/DataIntegrityTree.js +83 -29
- package/dist/DigNetwork/ContentServer.d.ts +6 -1
- package/dist/DigNetwork/ContentServer.d.ts.map +1 -1
- package/dist/DigNetwork/ContentServer.js +40 -16
- package/dist/DigNetwork/DigNetwork.d.ts +2 -5
- package/dist/DigNetwork/DigNetwork.d.ts.map +1 -1
- package/dist/DigNetwork/DigNetwork.js +119 -155
- package/dist/DigNetwork/DigPeer.d.ts +8 -3
- package/dist/DigNetwork/DigPeer.d.ts.map +1 -1
- package/dist/DigNetwork/DigPeer.js +116 -114
- package/dist/DigNetwork/PropagationServer.d.ts +8 -2
- package/dist/DigNetwork/PropagationServer.d.ts.map +1 -1
- package/dist/DigNetwork/PropagationServer.js +105 -73
- package/dist/blockchain/DataStore.d.ts +1 -4
- package/dist/blockchain/DataStore.d.ts.map +1 -1
- package/dist/blockchain/DataStore.js +5 -83
- package/dist/blockchain/DataStoreSerializer.d.ts +1 -1
- package/dist/blockchain/DataStoreSerializer.d.ts.map +1 -1
- package/dist/blockchain/FullNodePeer.d.ts +9 -1
- package/dist/blockchain/FullNodePeer.d.ts.map +1 -1
- package/dist/blockchain/FullNodePeer.js +60 -14
- package/dist/blockchain/ServerCoin.d.ts +11 -3
- package/dist/blockchain/ServerCoin.d.ts.map +1 -1
- package/dist/blockchain/ServerCoin.js +45 -17
- package/dist/blockchain/Wallet.d.ts +1 -1
- package/dist/blockchain/Wallet.d.ts.map +1 -1
- package/dist/blockchain/Wallet.js +1 -1
- package/dist/blockchain/coins.d.ts +1 -1
- package/dist/blockchain/coins.d.ts.map +1 -1
- package/dist/blockchain/coins.js +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/FileTransfer.d.ts +47 -0
- package/dist/utils/FileTransfer.d.ts.map +1 -0
- package/dist/utils/FileTransfer.js +209 -0
- package/dist/utils/StoreArchiveManager.d.ts +45 -0
- package/dist/utils/StoreArchiveManager.d.ts.map +1 -0
- package/dist/utils/StoreArchiveManager.js +153 -0
- package/dist/utils/config.d.ts +0 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +5 -12
- package/dist/utils/directoryUtils.d.ts +0 -6
- package/dist/utils/directoryUtils.d.ts.map +1 -1
- package/dist/utils/directoryUtils.js +30 -11
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +0 -1
- package/package.json +9 -3
- package/dist/utils/deltaUtils.d.ts +0 -2
- package/dist/utils/deltaUtils.d.ts.map +0 -1
- package/dist/utils/deltaUtils.js +0 -83
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import http from 'http';
|
|
1
2
|
import { Readable } from "stream";
|
|
2
3
|
export declare class PropagationServer {
|
|
3
4
|
private ipAddress;
|
|
@@ -10,7 +11,7 @@ export declare class PropagationServer {
|
|
|
10
11
|
private static readonly maxDelay;
|
|
11
12
|
private static readonly delayMultiplier;
|
|
12
13
|
constructor(ipAddress: string, storeId: string);
|
|
13
|
-
pushFile(
|
|
14
|
+
pushFile(fileLocation: string, dataPath: string): Promise<void>;
|
|
14
15
|
subscribeToStore(): Promise<void>;
|
|
15
16
|
unsubscribeFromStore(): Promise<void>;
|
|
16
17
|
getStoreStatus(): Promise<any>;
|
|
@@ -19,7 +20,12 @@ export declare class PropagationServer {
|
|
|
19
20
|
getStatus(): Promise<{
|
|
20
21
|
synced: boolean;
|
|
21
22
|
}>;
|
|
22
|
-
headStore(
|
|
23
|
+
headStore(options?: {
|
|
24
|
+
hasRootHash: string;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
success: boolean;
|
|
27
|
+
headers?: http.IncomingHttpHeaders;
|
|
28
|
+
}>;
|
|
23
29
|
isStoreSynced(): Promise<boolean>;
|
|
24
30
|
getUploadDetails(): Promise<{
|
|
25
31
|
nonce: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PropagationServer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/PropagationServer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PropagationServer.d.ts","sourceRoot":"","sources":["../../src/DigNetwork/PropagationServer.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,MAAM,CAAC;AAKxB,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAQ;IACpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAK;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAQ;IAC5C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAS;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAO;gBAElC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAYjC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/D,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAK9B,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAMpD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/C,SAAS,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAOzC,SAAS,CAAC,OAAO,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAA;KAAE,CAAC;IAW/G,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAMjC,gBAAgB,IAAI,OAAO,CAAC;QACvC,KAAK,EAAE,MAAM,CAAC;QACd,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;YAmBY,WAAW;YAyCX,kBAAkB;YAoElB,gBAAgB;YAgEhB,cAAc;YAiCd,KAAK;YAmDL,IAAI;YAmEJ,SAAS;YAuCT,2BAA2B;YAiC3B,gBAAgB;CAyC/B"}
|
|
@@ -9,7 +9,6 @@ const https_1 = __importDefault(require("https"));
|
|
|
9
9
|
const url_1 = require("url");
|
|
10
10
|
const ssl_1 = require("../utils/ssl");
|
|
11
11
|
const credentialsUtils_1 = require("../utils/credentialsUtils");
|
|
12
|
-
const spinnerUtils_1 = require("../utils/spinnerUtils");
|
|
13
12
|
const blockchain_1 = require("../blockchain");
|
|
14
13
|
class PropagationServer {
|
|
15
14
|
constructor(ipAddress, storeId) {
|
|
@@ -22,13 +21,13 @@ class PropagationServer {
|
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
// Method to upload a file to the propagation server
|
|
25
|
-
async pushFile(
|
|
24
|
+
async pushFile(fileLocation, dataPath) {
|
|
26
25
|
const { nonce, username, password } = await this.getUploadDetails();
|
|
27
26
|
const wallet = await blockchain_1.Wallet.load("default");
|
|
28
27
|
const keyOwnershipSig = await wallet.createKeyOwnershipSignature(nonce);
|
|
29
28
|
const publicKey = await wallet.getPublicSyntheticKey();
|
|
30
|
-
const uploadUrl = `https://${this.ipAddress}:${PropagationServer.port}/${this.storeId}/${
|
|
31
|
-
await this.retryOperation(() => this.uploadFileDirect(
|
|
29
|
+
const uploadUrl = `https://${this.ipAddress}:${PropagationServer.port}/${this.storeId}/${dataPath}`;
|
|
30
|
+
await this.retryOperation(() => this.uploadFileDirect(fileLocation, uploadUrl, username, password, keyOwnershipSig, publicKey.toString("hex"), nonce), `Upload failed for ${dataPath}`);
|
|
32
31
|
}
|
|
33
32
|
// Method to subscribe to a store on the propagation server
|
|
34
33
|
async subscribeToStore() {
|
|
@@ -62,8 +61,11 @@ class PropagationServer {
|
|
|
62
61
|
return JSON.parse(statusJson);
|
|
63
62
|
}
|
|
64
63
|
// Method to check if a specific store exists (HEAD request)
|
|
65
|
-
async headStore() {
|
|
66
|
-
|
|
64
|
+
async headStore(options) {
|
|
65
|
+
let url = `https://${this.ipAddress}:${PropagationServer.port}/${this.storeId}`;
|
|
66
|
+
if (options?.hasRootHash) {
|
|
67
|
+
url += `?hasRootHash=${options.hasRootHash}`;
|
|
68
|
+
}
|
|
67
69
|
return this.head(url);
|
|
68
70
|
}
|
|
69
71
|
// In PropagationServer.ts:
|
|
@@ -122,51 +124,49 @@ class PropagationServer {
|
|
|
122
124
|
// Method to fetch upload details from the server
|
|
123
125
|
async fetchUploadDetails(username, password) {
|
|
124
126
|
const remote = `https://${this.ipAddress}:${PropagationServer.port}/${this.storeId}`;
|
|
125
|
-
return (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
reject(new Error("Missing required headers in the response."));
|
|
157
|
-
}
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const url = new url_1.URL(remote);
|
|
129
|
+
const options = {
|
|
130
|
+
hostname: url.hostname,
|
|
131
|
+
port: url.port,
|
|
132
|
+
path: url.pathname,
|
|
133
|
+
method: "HEAD",
|
|
134
|
+
headers: {
|
|
135
|
+
Authorization: `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`,
|
|
136
|
+
},
|
|
137
|
+
key: fs_1.default.readFileSync(PropagationServer.keyPath),
|
|
138
|
+
cert: fs_1.default.readFileSync(PropagationServer.certPath),
|
|
139
|
+
rejectUnauthorized: false, // Allow self-signed certificates
|
|
140
|
+
};
|
|
141
|
+
const req = https_1.default.request(options, (res) => {
|
|
142
|
+
if (res.statusCode === 200) {
|
|
143
|
+
// Check if the headers are present and valid
|
|
144
|
+
const nonce = res.headers["x-nonce"];
|
|
145
|
+
const lastUploadedHash = res.headers?.["x-last-uploaded-hash"] ||
|
|
146
|
+
"0000000000000000000000000000000000000000000000000000000000000000";
|
|
147
|
+
const generationIndex = res.headers?.["x-generation-index"] || 0;
|
|
148
|
+
console.log({ nonce, lastUploadedHash, generationIndex });
|
|
149
|
+
if (nonce) {
|
|
150
|
+
resolve({
|
|
151
|
+
nonce: nonce,
|
|
152
|
+
lastUploadedHash: lastUploadedHash,
|
|
153
|
+
generationIndex: Number(generationIndex),
|
|
154
|
+
});
|
|
158
155
|
}
|
|
159
156
|
else {
|
|
160
|
-
reject(new Error(
|
|
157
|
+
reject(new Error("Missing required headers in the response."));
|
|
161
158
|
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
reject(new Error(`Failed to perform preflight check: ${res.statusCode} ${res.statusMessage}`));
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
req.on("error", (err) => {
|
|
165
|
+
console.error(err.message);
|
|
166
|
+
resolve(false); // Resolve to false if there is an error
|
|
168
167
|
});
|
|
169
|
-
|
|
168
|
+
req.end();
|
|
169
|
+
});
|
|
170
170
|
}
|
|
171
171
|
// Core method to upload a file directly to the server using a stream
|
|
172
172
|
async uploadFileDirect(filePath, uploadUrl, username, password, keyOwnershipSig, publicKey, nonce) {
|
|
@@ -271,38 +271,70 @@ class PropagationServer {
|
|
|
271
271
|
}
|
|
272
272
|
});
|
|
273
273
|
request.on("error", (error) => {
|
|
274
|
-
console.error(`Request error for ${url}:`, error);
|
|
274
|
+
console.error(`GET Request error for ${url}:`, error);
|
|
275
275
|
reject(error);
|
|
276
276
|
});
|
|
277
277
|
request.end();
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
280
|
// Helper method to perform HEAD requests
|
|
281
|
-
async head(url) {
|
|
281
|
+
async head(url, maxRedirects = 5) {
|
|
282
282
|
return new Promise((resolve, reject) => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
283
|
+
try {
|
|
284
|
+
// Parse the input URL
|
|
285
|
+
const urlObj = new url_1.URL(url);
|
|
286
|
+
const requestOptions = {
|
|
287
|
+
hostname: urlObj.hostname,
|
|
288
|
+
port: urlObj.port || (urlObj.protocol === "https:" ? 443 : undefined),
|
|
289
|
+
path: urlObj.pathname + urlObj.search,
|
|
290
|
+
method: "HEAD",
|
|
291
|
+
key: fs_1.default.readFileSync(PropagationServer.keyPath),
|
|
292
|
+
cert: fs_1.default.readFileSync(PropagationServer.certPath),
|
|
293
|
+
rejectUnauthorized: false,
|
|
294
|
+
};
|
|
295
|
+
const request = https_1.default.request(requestOptions, (response) => {
|
|
296
|
+
const { statusCode, headers } = response;
|
|
297
|
+
// If status code is 2xx, return success
|
|
298
|
+
if (statusCode && statusCode >= 200 && statusCode < 300) {
|
|
299
|
+
resolve({ success: true, headers });
|
|
300
|
+
}
|
|
301
|
+
// Handle 3xx redirection
|
|
302
|
+
else if (statusCode && statusCode >= 300 && statusCode < 400 && headers.location) {
|
|
303
|
+
if (maxRedirects > 0) {
|
|
304
|
+
let redirectUrl = headers.location;
|
|
305
|
+
// Check if the redirect URL is relative
|
|
306
|
+
if (!/^https?:\/\//i.test(redirectUrl)) {
|
|
307
|
+
// Resolve the relative URL based on the original URL
|
|
308
|
+
redirectUrl = new url_1.URL(redirectUrl, url).toString();
|
|
309
|
+
console.log(`Resolved relative redirect to: ${redirectUrl}`);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
console.log(`Redirecting to: ${redirectUrl}`);
|
|
313
|
+
}
|
|
314
|
+
// Recursively follow the redirection
|
|
315
|
+
this.head(redirectUrl, maxRedirects - 1)
|
|
316
|
+
.then(resolve)
|
|
317
|
+
.catch(reject);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
reject({ success: false, message: "Too many redirects" });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
// For other status codes, consider it a failure
|
|
325
|
+
resolve({ success: false });
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
request.on("error", (error) => {
|
|
329
|
+
console.error(`HEAD ${url}:`, error.message);
|
|
330
|
+
reject({ success: false });
|
|
331
|
+
});
|
|
332
|
+
request.end();
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
console.error(`Invalid URL: ${url}`, err.message);
|
|
336
|
+
reject({ success: false, message: "Invalid URL" });
|
|
337
|
+
}
|
|
306
338
|
});
|
|
307
339
|
}
|
|
308
340
|
// Helper method to fetch JSON data from a URL
|
|
@@ -400,7 +432,7 @@ class PropagationServer {
|
|
|
400
432
|
}
|
|
401
433
|
});
|
|
402
434
|
request.on("error", (error) => {
|
|
403
|
-
console.error(`
|
|
435
|
+
console.error(`GET ${url}:`, error.message);
|
|
404
436
|
reject(error);
|
|
405
437
|
});
|
|
406
438
|
request.end();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataStore as DataStoreDriver, DataStoreMetadata } from "datalayer-driver";
|
|
1
|
+
import { DataStore as DataStoreDriver, DataStoreMetadata } from "@dignetwork/datalayer-driver";
|
|
2
2
|
import { RootHistoryItem } from "../types";
|
|
3
3
|
import { DataIntegrityTree, DataIntegrityTreeOptions } from "../DataIntegrityTree";
|
|
4
4
|
import { CreateStoreUserInputs } from "../types";
|
|
@@ -44,13 +44,10 @@ export declare class DataStore {
|
|
|
44
44
|
}>;
|
|
45
45
|
private setCreationHeight;
|
|
46
46
|
getRootHistory(): Promise<RootHistoryItem[]>;
|
|
47
|
-
getLocalRootHistory(): Promise<RootHistoryItem[] | undefined>;
|
|
48
|
-
validate(): Promise<boolean>;
|
|
49
47
|
getMetaData(): Promise<DataStoreMetadata>;
|
|
50
48
|
isSynced(): Promise<boolean>;
|
|
51
49
|
hasMetaWritePermissions(publicSyntheticKey?: Buffer): Promise<boolean>;
|
|
52
50
|
updateMetadata(metadata: DataStoreMetadata): Promise<DataStoreDriver>;
|
|
53
51
|
getFileSetForRootHash(rootHash: string): Promise<string[]>;
|
|
54
|
-
getManifestHashes(): string[];
|
|
55
52
|
}
|
|
56
53
|
//# sourceMappingURL=DataStore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataStore.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,IAAI,eAAe,EAE5B,iBAAiB,EAIlB,MAAM,
|
|
1
|
+
{"version":3,"file":"DataStore.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,IAAI,eAAe,EAE5B,iBAAiB,EAIlB,MAAM,8BAA8B,CAAC;AAWtC,OAAO,EAAE,eAAe,EAAW,MAAM,UAAU,CAAC;AAGpD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAQjD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAoB;gBAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAiB/D,IAAW,OAAO,IAAI,MAAM,CAE3B;IAED,IAAW,IAAI,IAAI,iBAAiB,CAEnC;IAEM,QAAQ,IAAI,MAAM;IAIlB,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;WAMN,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;WAOtD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;WAK1C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;WAYnC,MAAM,CACxB,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,SAAS,CAAC;mBAyCA,IAAI;IA4FzB;;;OAGG;IACU,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAK5C;;;OAGG;WACiB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxD;;;;OAIG;mBACkB,mBAAmB;WAqB1B,YAAY,IAAI,SAAS,EAAE;IAW5B,aAAa,IAAI,OAAO,CAAC;QACpC,WAAW,EAAE,eAAe,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IAyGW,iBAAiB,IAAI,OAAO,CAAC;QACxC,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;YA0BY,iBAAiB;IAYlB,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAuB5C,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAM5B,uBAAuB,CAClC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC;IAkBN,cAAc,CACzB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,eAAe,CAAC;IA+Cd,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAgCxE"}
|
|
@@ -6,13 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.DataStore = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const datalayer_driver_1 = require("datalayer-driver");
|
|
9
|
+
const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
|
|
10
10
|
const util_1 = require("util");
|
|
11
11
|
const FullNodePeer_1 = require("./FullNodePeer");
|
|
12
12
|
const Wallet_1 = require("./Wallet");
|
|
13
13
|
const config_1 = require("../utils/config");
|
|
14
14
|
const coins_1 = require("./coins");
|
|
15
|
-
const utils_1 = require("../utils");
|
|
16
15
|
const hashUtils_1 = require("../utils/hashUtils");
|
|
17
16
|
const DataIntegrityTree_1 = require("../DataIntegrityTree");
|
|
18
17
|
const prompts_1 = require("../prompts");
|
|
@@ -293,88 +292,17 @@ class DataStore {
|
|
|
293
292
|
return rootHashes.map((rootHash, index) => ({
|
|
294
293
|
root_hash: rootHash.toString("hex"),
|
|
295
294
|
timestamp: Number(rootHashesTimestamps?.[index].toString()),
|
|
295
|
+
synced: fs_1.default.existsSync(`${config_1.STORE_PATH}/${this.storeId}/${rootHash}.dat`),
|
|
296
296
|
}));
|
|
297
297
|
}
|
|
298
|
-
async getLocalRootHistory() {
|
|
299
|
-
const manifestFilePath = (0, config_1.getManifestFilePath)(this.storeId);
|
|
300
|
-
if (!fs_1.default.existsSync(manifestFilePath)) {
|
|
301
|
-
console.error("Manifest file not found", manifestFilePath);
|
|
302
|
-
return undefined;
|
|
303
|
-
}
|
|
304
|
-
const manifestHashes = fs_1.default
|
|
305
|
-
.readFileSync(manifestFilePath, "utf-8")
|
|
306
|
-
.split("\n")
|
|
307
|
-
.filter(Boolean);
|
|
308
|
-
return manifestHashes.map((rootHash) => ({
|
|
309
|
-
root_hash: rootHash,
|
|
310
|
-
timestamp: 0, // Timestamps are not yet included in the manifest
|
|
311
|
-
}));
|
|
312
|
-
}
|
|
313
|
-
async validate() {
|
|
314
|
-
const rootHistory = await this.getRootHistory();
|
|
315
|
-
const manifestFilePath = (0, config_1.getManifestFilePath)(this.storeId);
|
|
316
|
-
if (!fs_1.default.existsSync(manifestFilePath)) {
|
|
317
|
-
console.error("Manifest file not found", manifestFilePath);
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
const manifestHashes = fs_1.default
|
|
321
|
-
.readFileSync(manifestFilePath, "utf-8")
|
|
322
|
-
.split("\n")
|
|
323
|
-
.filter(Boolean);
|
|
324
|
-
if (manifestHashes.length > rootHistory.length) {
|
|
325
|
-
console.error("The store is corrupted: Manifest file has more hashes than the root history.");
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
if (rootHistory.length > manifestHashes.length) {
|
|
329
|
-
console.error("The store is not synced: Root history has more hashes than the manifest file.");
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
for (let i = 0; i < manifestHashes.length; i++) {
|
|
333
|
-
if (manifestHashes[i] !== rootHistory[i]?.root_hash) {
|
|
334
|
-
console.error(`Root hash mismatch at position ${i}: expected ${manifestHashes[i]} but found ${rootHistory[i]?.root_hash}`);
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
let filesIntegrityIntact = true;
|
|
339
|
-
for (const rootHash of manifestHashes) {
|
|
340
|
-
const datFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash}.dat`);
|
|
341
|
-
if (!fs_1.default.existsSync(datFilePath)) {
|
|
342
|
-
console.error(`Data file for root hash ${rootHash} not found`);
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
const datFileContent = JSON.parse(fs_1.default.readFileSync(datFilePath, "utf-8"));
|
|
346
|
-
if (datFileContent.root !== rootHash) {
|
|
347
|
-
console.error(`Root hash in data file does not match: ${datFileContent.root} !== ${rootHash}`);
|
|
348
|
-
return false;
|
|
349
|
-
}
|
|
350
|
-
for (const [fileKey, fileData] of Object.entries(datFileContent.files)) {
|
|
351
|
-
const integrityCheck = (0, utils_1.validateFileSha256)(fileData.sha256, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
|
|
352
|
-
if (!integrityCheck) {
|
|
353
|
-
filesIntegrityIntact = false;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
if (!filesIntegrityIntact) {
|
|
358
|
-
console.error("Store Corrupted: Data failed SHA256 validation.");
|
|
359
|
-
return false;
|
|
360
|
-
}
|
|
361
|
-
return true;
|
|
362
|
-
}
|
|
363
298
|
async getMetaData() {
|
|
364
299
|
const { latestStore } = await this.fetchCoinInfo();
|
|
365
300
|
return latestStore.metadata;
|
|
366
301
|
}
|
|
367
302
|
async isSynced() {
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
373
|
-
const manifestHashes = fs_1.default
|
|
374
|
-
.readFileSync(manifestFilePath, "utf-8")
|
|
375
|
-
.split("\n")
|
|
376
|
-
.filter(Boolean);
|
|
377
|
-
return rootHistory.length === manifestHashes.length;
|
|
303
|
+
const dataStore = await DataStore.from(this.storeId);
|
|
304
|
+
const rootHistory = await dataStore.getRootHistory();
|
|
305
|
+
return !rootHistory.some((root) => !root.synced);
|
|
378
306
|
}
|
|
379
307
|
async hasMetaWritePermissions(publicSyntheticKey) {
|
|
380
308
|
const wallet = await Wallet_1.Wallet.load("default");
|
|
@@ -423,11 +351,5 @@ class DataStore {
|
|
|
423
351
|
}
|
|
424
352
|
return filesInvolved;
|
|
425
353
|
}
|
|
426
|
-
getManifestHashes() {
|
|
427
|
-
const manifestFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, "manifest.dat");
|
|
428
|
-
return fs_1.default.existsSync(manifestFilePath)
|
|
429
|
-
? fs_1.default.readFileSync(manifestFilePath, "utf-8").split("\n").filter(Boolean)
|
|
430
|
-
: [];
|
|
431
|
-
}
|
|
432
354
|
}
|
|
433
355
|
exports.DataStore = DataStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataStoreSerializer.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStoreSerializer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAKV,MAAM,
|
|
1
|
+
{"version":3,"file":"DataStoreSerializer.d.ts","sourceRoot":"","sources":["../../src/blockchain/DataStoreSerializer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAKV,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;gBAEf,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAOnE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAgDF,WAAW,CACvB,IAAI,EAAE;QACJ,WAAW,EAAE,GAAG,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,GACA;QACD,WAAW,EAAE,SAAS,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB;CAuEF"}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import { Peer } from "datalayer-driver";
|
|
1
|
+
import { Peer } from "@dignetwork/datalayer-driver";
|
|
2
2
|
export declare class FullNodePeer {
|
|
3
3
|
private static cachedPeer;
|
|
4
4
|
private static memoizedFetchNewPeerIPs;
|
|
5
5
|
private peer;
|
|
6
|
+
private static deprioritizedIps;
|
|
6
7
|
private constructor();
|
|
7
8
|
static connect(): Promise<Peer>;
|
|
8
9
|
private static isPortReachable;
|
|
9
10
|
private static isValidIpAddress;
|
|
11
|
+
/**
|
|
12
|
+
* Retrieves the TRUSTED_FULLNODE IP from the environment
|
|
13
|
+
* and verifies if it is a valid IP address.
|
|
14
|
+
*
|
|
15
|
+
* @returns {string | null} The valid IP address or null if invalid
|
|
16
|
+
*/
|
|
17
|
+
private static getTrustedFullNode;
|
|
10
18
|
private static fetchNewPeerIPs;
|
|
11
19
|
private static getPeerIPs;
|
|
12
20
|
private static createPeerProxy;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FullNodePeer.d.ts","sourceRoot":"","sources":["../../src/blockchain/FullNodePeer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"FullNodePeer.d.ts","sourceRoot":"","sources":["../../src/blockchain/FullNodePeer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AAoBpD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkD;IAC3E,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAA0B;IAChE,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAA0B;IAMzD,OAAO;WAIa,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5C,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAM/B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;mBASZ,eAAe;mBA2Df,UAAU;IA2B/B,OAAO,CAAC,MAAM,CAAC,eAAe;mBAkDT,WAAW;IA+FzB,OAAO,IAAI,IAAI;WAIF,mBAAmB,CACrC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC;CAwBpB"}
|
|
@@ -7,7 +7,7 @@ exports.FullNodePeer = void 0;
|
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const os_1 = __importDefault(require("os"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
|
-
const datalayer_driver_1 = require("datalayer-driver");
|
|
10
|
+
const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
|
|
11
11
|
const chia_server_coin_1 = require("chia-server-coin");
|
|
12
12
|
const promises_1 = require("dns/promises");
|
|
13
13
|
const net_1 = __importDefault(require("net"));
|
|
@@ -16,6 +16,7 @@ const nanospinner_1 = require("nanospinner");
|
|
|
16
16
|
const config_1 = require("../utils/config");
|
|
17
17
|
const FULLNODE_PORT = 8444;
|
|
18
18
|
const LOCALHOST = "127.0.0.1";
|
|
19
|
+
const CHIA_NODES_HOST = "chia-nodes";
|
|
19
20
|
const DNS_HOSTS = [
|
|
20
21
|
"dns-introducer.chia.net",
|
|
21
22
|
"chia.ctrlaltdel.ch",
|
|
@@ -48,19 +49,38 @@ class FullNodePeer {
|
|
|
48
49
|
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
49
50
|
return ipv4Regex.test(ip);
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves the TRUSTED_FULLNODE IP from the environment
|
|
54
|
+
* and verifies if it is a valid IP address.
|
|
55
|
+
*
|
|
56
|
+
* @returns {string | null} The valid IP address or null if invalid
|
|
57
|
+
*/
|
|
58
|
+
static getTrustedFullNode() {
|
|
52
59
|
const trustedNodeIp = process.env.TRUSTED_FULLNODE || null;
|
|
60
|
+
if (trustedNodeIp && FullNodePeer.isValidIpAddress(trustedNodeIp)) {
|
|
61
|
+
return trustedNodeIp;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
static async fetchNewPeerIPs() {
|
|
66
|
+
const trustedNodeIp = FullNodePeer.getTrustedFullNode();
|
|
53
67
|
const priorityIps = [];
|
|
54
|
-
// Prioritize trustedNodeIp
|
|
68
|
+
// Prioritize trustedNodeIp unless it's deprioritized
|
|
55
69
|
if (trustedNodeIp &&
|
|
56
|
-
FullNodePeer.
|
|
70
|
+
!FullNodePeer.deprioritizedIps.has(trustedNodeIp) &&
|
|
57
71
|
(await FullNodePeer.isPortReachable(trustedNodeIp, FULLNODE_PORT))) {
|
|
58
72
|
priorityIps.push(trustedNodeIp);
|
|
59
73
|
}
|
|
60
|
-
// Prioritize LOCALHOST
|
|
61
|
-
if (
|
|
74
|
+
// Prioritize LOCALHOST unless it's deprioritized
|
|
75
|
+
if (!FullNodePeer.deprioritizedIps.has(LOCALHOST) &&
|
|
76
|
+
(await FullNodePeer.isPortReachable(LOCALHOST, FULLNODE_PORT))) {
|
|
62
77
|
priorityIps.push(LOCALHOST);
|
|
63
78
|
}
|
|
79
|
+
// Prioritize CHIA_NODES_HOST unless it's deprioritized
|
|
80
|
+
if (!FullNodePeer.deprioritizedIps.has(CHIA_NODES_HOST) &&
|
|
81
|
+
(await FullNodePeer.isPortReachable(CHIA_NODES_HOST, FULLNODE_PORT))) {
|
|
82
|
+
priorityIps.push(CHIA_NODES_HOST);
|
|
83
|
+
}
|
|
64
84
|
if (priorityIps.length > 0) {
|
|
65
85
|
return priorityIps;
|
|
66
86
|
}
|
|
@@ -102,23 +122,47 @@ class FullNodePeer {
|
|
|
102
122
|
}
|
|
103
123
|
// @ts-ignore
|
|
104
124
|
if (FullNodePeer.memoizedFetchNewPeerIPs?.cache?.clear) {
|
|
125
|
+
// Clear cache and reset deprioritized IPs when cache is cleared
|
|
126
|
+
FullNodePeer.deprioritizedIps.clear();
|
|
105
127
|
// @ts-ignore
|
|
106
128
|
FullNodePeer.memoizedFetchNewPeerIPs.cache.clear();
|
|
107
129
|
}
|
|
108
130
|
return FullNodePeer.memoizedFetchNewPeerIPs();
|
|
109
131
|
}
|
|
110
|
-
static createPeerProxy(peer
|
|
132
|
+
static createPeerProxy(peer) {
|
|
111
133
|
return new Proxy(peer, {
|
|
112
134
|
get: (target, prop) => {
|
|
113
135
|
const originalMethod = target[prop];
|
|
114
136
|
if (typeof originalMethod === "function") {
|
|
115
137
|
return async (...args) => {
|
|
138
|
+
let timeoutId;
|
|
139
|
+
// Start the timeout to forget the peer after 1 minute
|
|
140
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
141
|
+
timeoutId = setTimeout(() => {
|
|
142
|
+
FullNodePeer.cachedPeer = null;
|
|
143
|
+
reject(new Error("Operation timed out. Reconnecting to a new peer."));
|
|
144
|
+
}, 60000); // 1 minute
|
|
145
|
+
});
|
|
116
146
|
try {
|
|
117
|
-
|
|
147
|
+
// Run the original method and race it against the timeout
|
|
148
|
+
const result = await Promise.race([
|
|
149
|
+
originalMethod.apply(target, args),
|
|
150
|
+
timeoutPromise,
|
|
151
|
+
]);
|
|
152
|
+
// Clear the timeout if the operation succeeded
|
|
153
|
+
if (timeoutId) {
|
|
154
|
+
clearTimeout(timeoutId);
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
118
157
|
}
|
|
119
158
|
catch (error) {
|
|
120
|
-
|
|
159
|
+
// If the error is WebSocket-related or timeout, reset the peer
|
|
160
|
+
if (error.message.includes("WebSocket") || error.message.includes("Operation timed out")) {
|
|
121
161
|
FullNodePeer.cachedPeer = null;
|
|
162
|
+
// @ts-ignore
|
|
163
|
+
FullNodePeer.memoizedFetchNewPeerIPs.cache.clear();
|
|
164
|
+
FullNodePeer.deprioritizedIps.clear();
|
|
165
|
+
console.info(`Fullnode Peer error, reconnecting to a new peer...`);
|
|
122
166
|
const newPeer = await FullNodePeer.getBestPeer();
|
|
123
167
|
return newPeer[prop](...args);
|
|
124
168
|
}
|
|
@@ -149,7 +193,7 @@ class FullNodePeer {
|
|
|
149
193
|
if (ip) {
|
|
150
194
|
try {
|
|
151
195
|
const peer = await datalayer_driver_1.Peer.new(`${ip}:${FULLNODE_PORT}`, false, certFile, keyFile);
|
|
152
|
-
return FullNodePeer.createPeerProxy(peer
|
|
196
|
+
return FullNodePeer.createPeerProxy(peer);
|
|
153
197
|
}
|
|
154
198
|
catch (error) {
|
|
155
199
|
console.error(`Failed to create peer for IP ${ip}: ${error.message}`);
|
|
@@ -174,16 +218,17 @@ class FullNodePeer {
|
|
|
174
218
|
throw new Error("No valid peak heights obtained from any peer.");
|
|
175
219
|
}
|
|
176
220
|
const highestPeak = Math.max(...validHeights);
|
|
177
|
-
// Prioritize LOCALHOST and
|
|
221
|
+
// Prioritize LOCALHOST, TRUSTED_NODE_IP, and CHIA_NODES_HOST if they have the highest peak height
|
|
178
222
|
let bestPeerIndex = validHeights.findIndex((height, index) => height === highestPeak &&
|
|
179
|
-
(peerIPs[index]
|
|
180
|
-
|
|
223
|
+
!FullNodePeer.deprioritizedIps.has(peerIPs[index]) && // Exclude deprioritized IPs
|
|
224
|
+
(peerIPs[index] === LOCALHOST || peerIPs[index] === trustedNodeIp || peerIPs[index] === CHIA_NODES_HOST));
|
|
225
|
+
// If LOCALHOST, TRUSTED_NODE_IP, or CHIA_NODES_HOST don't have the highest peak, select any peer with the highest peak
|
|
181
226
|
if (bestPeerIndex === -1) {
|
|
182
227
|
bestPeerIndex = validHeights.findIndex((height) => height === highestPeak);
|
|
183
228
|
}
|
|
184
229
|
const bestPeer = peers[bestPeerIndex];
|
|
185
230
|
FullNodePeer.cachedPeer = { peer: bestPeer, timestamp: now };
|
|
186
|
-
console.log(`Using Peer: ${peerIPs[bestPeerIndex]}`);
|
|
231
|
+
console.log(`Using Fullnode Peer: ${peerIPs[bestPeerIndex]}`);
|
|
187
232
|
return bestPeer;
|
|
188
233
|
}
|
|
189
234
|
getPeer() {
|
|
@@ -210,6 +255,7 @@ class FullNodePeer {
|
|
|
210
255
|
}
|
|
211
256
|
exports.FullNodePeer = FullNodePeer;
|
|
212
257
|
FullNodePeer.cachedPeer = null;
|
|
258
|
+
FullNodePeer.deprioritizedIps = new Set(); // New set for deprioritized IPs
|
|
213
259
|
(() => {
|
|
214
260
|
FullNodePeer.memoizedFetchNewPeerIPs = (0, lodash_1.memoize)(FullNodePeer.fetchNewPeerIPs);
|
|
215
261
|
})();
|