@dignetwork/dig-sdk 0.0.1-alpha.7 → 0.0.1-alpha.70
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 +5 -2
- package/dist/DataIntegrityTree/DataIntegrityTree.d.ts.map +1 -1
- package/dist/DataIntegrityTree/DataIntegrityTree.js +94 -34
- package/dist/DigNetwork/ContentServer.d.ts +9 -4
- package/dist/DigNetwork/ContentServer.d.ts.map +1 -1
- package/dist/DigNetwork/ContentServer.js +55 -19
- package/dist/DigNetwork/DigNetwork.d.ts +3 -8
- package/dist/DigNetwork/DigNetwork.d.ts.map +1 -1
- package/dist/DigNetwork/DigNetwork.js +115 -171
- package/dist/DigNetwork/DigPeer.d.ts +9 -3
- package/dist/DigNetwork/DigPeer.d.ts.map +1 -1
- package/dist/DigNetwork/DigPeer.js +68 -114
- package/dist/DigNetwork/PropagationServer.d.ts +91 -33
- package/dist/DigNetwork/PropagationServer.d.ts.map +1 -1
- package/dist/DigNetwork/PropagationServer.js +414 -372
- package/dist/blockchain/DataStore.d.ts +13 -6
- package/dist/blockchain/DataStore.d.ts.map +1 -1
- package/dist/blockchain/DataStore.js +64 -91
- 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 +38 -10
- 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 +2 -2
- package/dist/blockchain/Wallet.d.ts.map +1 -1
- package/dist/blockchain/Wallet.js +2 -2
- 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/ContentScanner.d.ts +63 -0
- package/dist/utils/ContentScanner.d.ts.map +1 -0
- package/dist/utils/ContentScanner.js +175 -0
- 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 +2 -3
- 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 +12 -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,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";
|
|
@@ -13,7 +13,7 @@ export declare class DataStore {
|
|
|
13
13
|
serialize(): string;
|
|
14
14
|
static getActiveStore(): Promise<DataStore | undefined>;
|
|
15
15
|
static deserialize(serialized: string): DataStore;
|
|
16
|
-
static from(storeId: string | Buffer): DataStore;
|
|
16
|
+
static from(storeId: string | Buffer, rootHash?: string): DataStore;
|
|
17
17
|
static create(inputs?: CreateStoreUserInputs): Promise<DataStore>;
|
|
18
18
|
private static mint;
|
|
19
19
|
/**
|
|
@@ -44,13 +44,20 @@ export declare class DataStore {
|
|
|
44
44
|
}>;
|
|
45
45
|
private setCreationHeight;
|
|
46
46
|
getRootHistory(): Promise<RootHistoryItem[]>;
|
|
47
|
-
|
|
48
|
-
validate(): Promise<boolean>;
|
|
47
|
+
generateManifestFile(folderPath?: string): Promise<void>;
|
|
49
48
|
getMetaData(): Promise<DataStoreMetadata>;
|
|
50
49
|
isSynced(): Promise<boolean>;
|
|
51
50
|
hasMetaWritePermissions(publicSyntheticKey?: Buffer): Promise<boolean>;
|
|
52
51
|
updateMetadata(metadata: DataStoreMetadata): Promise<DataStoreDriver>;
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Retrieve the file set for a given root hash and validate file integrity.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} rootHash - The root hash to fetch the file set.
|
|
56
|
+
* @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
|
|
57
|
+
*/
|
|
58
|
+
getFileSetForRootHash(rootHash: string): Promise<{
|
|
59
|
+
name: string;
|
|
60
|
+
path: string;
|
|
61
|
+
}[]>;
|
|
55
62
|
}
|
|
56
63
|
//# 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;AAYjD,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,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS;WAiBtD,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;IAwC5C,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAexD,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+C3B;;;;;OAKG;IACU,qBAAqB,CAChC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAsD7C"}
|
|
@@ -6,18 +6,21 @@ 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
|
|
15
|
+
const colorette_1 = require("colorette");
|
|
16
16
|
const hashUtils_1 = require("../utils/hashUtils");
|
|
17
17
|
const DataIntegrityTree_1 = require("../DataIntegrityTree");
|
|
18
18
|
const prompts_1 = require("../prompts");
|
|
19
19
|
const FileCache_1 = require("../utils/FileCache");
|
|
20
20
|
const DataStoreSerializer_1 = require("./DataStoreSerializer");
|
|
21
|
+
const node_cache_1 = __importDefault(require("node-cache"));
|
|
22
|
+
// Initialize the cache with a TTL of 180 seconds (3 minutes)
|
|
23
|
+
const rootHistoryCache = new node_cache_1.default({ stdTTL: 180 });
|
|
21
24
|
const stat = (0, util_1.promisify)(fs_1.default.stat);
|
|
22
25
|
const readdir = (0, util_1.promisify)(fs_1.default.readdir);
|
|
23
26
|
class DataStore {
|
|
@@ -62,12 +65,15 @@ class DataStore {
|
|
|
62
65
|
const parsed = JSON.parse(serialized);
|
|
63
66
|
return new DataStore(parsed.storeId);
|
|
64
67
|
}
|
|
65
|
-
static from(storeId) {
|
|
68
|
+
static from(storeId, rootHash) {
|
|
66
69
|
const existingTreeOptions = {
|
|
67
70
|
storageMode: "local",
|
|
68
71
|
storeDir: config_1.STORE_PATH,
|
|
69
72
|
disableInitialize: true,
|
|
70
73
|
};
|
|
74
|
+
if (rootHash) {
|
|
75
|
+
existingTreeOptions.rootHash = rootHash;
|
|
76
|
+
}
|
|
71
77
|
if (storeId instanceof Buffer) {
|
|
72
78
|
return new DataStore(storeId.toString("hex"), existingTreeOptions);
|
|
73
79
|
}
|
|
@@ -284,97 +290,49 @@ class DataStore {
|
|
|
284
290
|
});
|
|
285
291
|
}
|
|
286
292
|
async getRootHistory() {
|
|
293
|
+
// Check if the root history is cached for this storeId
|
|
294
|
+
const cachedHistory = rootHistoryCache.get(this.storeId);
|
|
295
|
+
if (cachedHistory) {
|
|
296
|
+
return cachedHistory;
|
|
297
|
+
}
|
|
298
|
+
// Fetch root history from peer if not cached
|
|
287
299
|
const peer = await FullNodePeer_1.FullNodePeer.connect();
|
|
288
300
|
const { createdAtHeight, createdAtHash } = await this.getCreationHeight();
|
|
289
301
|
const { rootHashes, rootHashesTimestamps } = await peer.syncStoreFromLauncherId(Buffer.from(this.storeId, "hex"), createdAtHeight, createdAtHash, true);
|
|
290
302
|
if (!rootHashes) {
|
|
291
303
|
return [];
|
|
292
304
|
}
|
|
293
|
-
|
|
305
|
+
// Build the root history list
|
|
306
|
+
const rootHistory = rootHashes.map((rootHash, index) => ({
|
|
294
307
|
root_hash: rootHash.toString("hex"),
|
|
295
308
|
timestamp: Number(rootHashesTimestamps?.[index].toString()),
|
|
309
|
+
synced: fs_1.default.existsSync(path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash.toString("hex")}.dat`)),
|
|
296
310
|
}));
|
|
311
|
+
// Store the root history in the cache
|
|
312
|
+
rootHistoryCache.set(this.storeId, rootHistory);
|
|
313
|
+
return rootHistory;
|
|
297
314
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
315
|
+
// Generates a fresh manifest file based on the current root history
|
|
316
|
+
// and what is currently on disk
|
|
317
|
+
async generateManifestFile(folderPath) {
|
|
318
|
+
if (!folderPath) {
|
|
319
|
+
folderPath = path_1.default.join(config_1.STORE_PATH, this.storeId, "data");
|
|
303
320
|
}
|
|
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
321
|
const rootHistory = await this.getRootHistory();
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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;
|
|
322
|
+
// Need this for the dataintegrity tree to work properly
|
|
323
|
+
fs_1.default.writeFileSync(path_1.default.join(folderPath, "manifest.dat"), rootHistory
|
|
324
|
+
.filter((root) => root.synced)
|
|
325
|
+
.map((root) => root.root_hash)
|
|
326
|
+
.join("\n"));
|
|
362
327
|
}
|
|
363
328
|
async getMetaData() {
|
|
364
329
|
const { latestStore } = await this.fetchCoinInfo();
|
|
365
330
|
return latestStore.metadata;
|
|
366
331
|
}
|
|
367
332
|
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;
|
|
333
|
+
const dataStore = await DataStore.from(this.storeId);
|
|
334
|
+
const rootHistory = await dataStore.getRootHistory();
|
|
335
|
+
return !rootHistory.some((root) => !root.synced);
|
|
378
336
|
}
|
|
379
337
|
async hasMetaWritePermissions(publicSyntheticKey) {
|
|
380
338
|
const wallet = await Wallet_1.Wallet.load("default");
|
|
@@ -407,27 +365,42 @@ class DataStore {
|
|
|
407
365
|
}
|
|
408
366
|
return updateStoreResponse.newStore;
|
|
409
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Retrieve the file set for a given root hash and validate file integrity.
|
|
370
|
+
*
|
|
371
|
+
* @param {string} rootHash - The root hash to fetch the file set.
|
|
372
|
+
* @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
|
|
373
|
+
*/
|
|
410
374
|
async getFileSetForRootHash(rootHash) {
|
|
411
375
|
const datFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, `${rootHash}.dat`);
|
|
412
376
|
const datFileContent = JSON.parse(fs_1.default.readFileSync(datFilePath, "utf-8"));
|
|
413
377
|
const heightDatFilePath = path_1.default.join(config_1.STORE_PATH, this.storeId, "height.json");
|
|
414
|
-
|
|
415
|
-
const filesInvolved =
|
|
416
|
-
filesInvolved.
|
|
417
|
-
|
|
418
|
-
|
|
378
|
+
// Use a Set to ensure uniqueness
|
|
379
|
+
const filesInvolved = new Set();
|
|
380
|
+
filesInvolved.add({
|
|
381
|
+
name: "height.json",
|
|
382
|
+
path: "height.json",
|
|
383
|
+
});
|
|
384
|
+
// Iterate over each file and perform an integrity check
|
|
419
385
|
for (const [fileKey, fileData] of Object.entries(datFileContent.files)) {
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
386
|
+
const filePath = (0, hashUtils_1.getFilePathFromSha256)(datFileContent.files[fileKey].sha256, "data");
|
|
387
|
+
// Perform the integrity check
|
|
388
|
+
const integrityCheck = await DataIntegrityTree_1.DataIntegrityTree.validateKeyIntegrityWithForeignTree(fileKey, datFileContent.files[fileKey].sha256, datFileContent, rootHash, path_1.default.join(config_1.STORE_PATH, this.storeId, "data"));
|
|
389
|
+
if (integrityCheck) {
|
|
390
|
+
console.log((0, colorette_1.green)(`✔ File ${fileKey} has passed the integrity check.`));
|
|
391
|
+
// Add the file to the Set
|
|
392
|
+
filesInvolved.add({
|
|
393
|
+
name: Buffer.from(fileKey, "hex").toString("utf-8"),
|
|
394
|
+
path: filePath,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
console.error((0, colorette_1.red)(`File ${fileKey} failed the integrity check.`));
|
|
399
|
+
throw new Error(`Integrity check failed for file: ${fileKey}. Aborting.`);
|
|
400
|
+
}
|
|
423
401
|
}
|
|
424
|
-
return
|
|
425
|
-
|
|
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
|
-
: [];
|
|
402
|
+
// Convert Set to Array and return
|
|
403
|
+
return Array.from(filesInvolved);
|
|
431
404
|
}
|
|
432
405
|
}
|
|
433
406
|
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,6 +122,8 @@ 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
|
}
|
|
@@ -137,6 +159,10 @@ class FullNodePeer {
|
|
|
137
159
|
// If the error is WebSocket-related or timeout, reset the peer
|
|
138
160
|
if (error.message.includes("WebSocket") || error.message.includes("Operation timed out")) {
|
|
139
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...`);
|
|
140
166
|
const newPeer = await FullNodePeer.getBestPeer();
|
|
141
167
|
return newPeer[prop](...args);
|
|
142
168
|
}
|
|
@@ -192,16 +218,17 @@ class FullNodePeer {
|
|
|
192
218
|
throw new Error("No valid peak heights obtained from any peer.");
|
|
193
219
|
}
|
|
194
220
|
const highestPeak = Math.max(...validHeights);
|
|
195
|
-
// Prioritize LOCALHOST and
|
|
221
|
+
// Prioritize LOCALHOST, TRUSTED_NODE_IP, and CHIA_NODES_HOST if they have the highest peak height
|
|
196
222
|
let bestPeerIndex = validHeights.findIndex((height, index) => height === highestPeak &&
|
|
197
|
-
(peerIPs[index]
|
|
198
|
-
|
|
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
|
|
199
226
|
if (bestPeerIndex === -1) {
|
|
200
227
|
bestPeerIndex = validHeights.findIndex((height) => height === highestPeak);
|
|
201
228
|
}
|
|
202
229
|
const bestPeer = peers[bestPeerIndex];
|
|
203
230
|
FullNodePeer.cachedPeer = { peer: bestPeer, timestamp: now };
|
|
204
|
-
console.log(`Using Peer: ${peerIPs[bestPeerIndex]}`);
|
|
231
|
+
console.log(`Using Fullnode Peer: ${peerIPs[bestPeerIndex]}`);
|
|
205
232
|
return bestPeer;
|
|
206
233
|
}
|
|
207
234
|
getPeer() {
|
|
@@ -228,6 +255,7 @@ class FullNodePeer {
|
|
|
228
255
|
}
|
|
229
256
|
exports.FullNodePeer = FullNodePeer;
|
|
230
257
|
FullNodePeer.cachedPeer = null;
|
|
258
|
+
FullNodePeer.deprioritizedIps = new Set(); // New set for deprioritized IPs
|
|
231
259
|
(() => {
|
|
232
260
|
FullNodePeer.memoizedFetchNewPeerIPs = (0, lodash_1.memoize)(FullNodePeer.fetchNewPeerIPs);
|
|
233
261
|
})();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServerCoin as ServerCoinDriver } from "datalayer-driver";
|
|
1
|
+
import { ServerCoin as ServerCoinDriver } from "@dignetwork/datalayer-driver";
|
|
2
2
|
import { NconfManager } from "../utils/NconfManager";
|
|
3
3
|
export declare class ServerCoin {
|
|
4
4
|
private storeId;
|
|
@@ -8,14 +8,22 @@ export declare class ServerCoin {
|
|
|
8
8
|
saveServerCoinData(serverCoin: ServerCoinDriver, epoch: number, peerIp: string): Promise<void>;
|
|
9
9
|
melt(epoch: number, peerIp: string): Promise<void>;
|
|
10
10
|
private removeServerCoinData;
|
|
11
|
+
getAllEpochPeers(epoch: number, blacklist?: string[]): Promise<string[]>;
|
|
12
|
+
getActiveEpochPeers(blacklist?: string[]): Promise<string[]>;
|
|
11
13
|
sampleCurrentEpoch(sampleSize?: number, blacklist?: string[]): Promise<string[]>;
|
|
12
14
|
sampleServerCoinsByEpoch(epoch: number, sampleSize?: number, blacklist?: string[]): Promise<string[]>;
|
|
13
|
-
static getCurrentEpoch():
|
|
15
|
+
static getCurrentEpoch(): {
|
|
16
|
+
epoch: number;
|
|
17
|
+
round: number;
|
|
18
|
+
};
|
|
14
19
|
ensureServerCoinExists(peerIp: string): Promise<void>;
|
|
15
20
|
meltOutdatedEpochs(peerIp: string): Promise<void>;
|
|
16
21
|
static meltUntrackedStoreCoins(): Promise<void>;
|
|
17
22
|
private getServerCoinsForStore;
|
|
18
23
|
hasEpochCoinBeenCreated(currentEpoch: number, peerIp: string): Promise<boolean>;
|
|
19
|
-
static
|
|
24
|
+
static calculateEpochAndRound(currentTimestampUTC: Date): {
|
|
25
|
+
epoch: number;
|
|
26
|
+
round: number;
|
|
27
|
+
};
|
|
20
28
|
}
|
|
21
29
|
//# sourceMappingURL=ServerCoin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerCoin.d.ts","sourceRoot":"","sources":["../../src/blockchain/ServerCoin.ts"],"names":[],"mappings":"AACA,OAAO,EAML,UAAU,IAAI,gBAAgB,EAE/B,MAAM,
|
|
1
|
+
{"version":3,"file":"ServerCoin.d.ts","sourceRoot":"","sources":["../../src/blockchain/ServerCoin.ts"],"names":[],"mappings":"AACA,OAAO,EAML,UAAU,IAAI,gBAAgB,EAE/B,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAUrD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,gBAAuB,iBAAiB,eAEtC;gBAEU,OAAO,EAAE,MAAM;IAKd,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2DzD,kBAAkB,CAC7B,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAqBH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAoDjD,oBAAoB;IAerB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA2C5E,mBAAmB,CAC9B,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,kBAAkB,CAC7B,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;IAMP,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAM,EAAO,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC;WASN,eAAe,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAKpD,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDrD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WA+B1C,uBAAuB;YAkE7B,sBAAsB;IAWvB,uBAAuB,CAClC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;WAuBL,sBAAsB,CAAC,mBAAmB,EAAE,IAAI,GAAG;QAC/D,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf;CA2BF"}
|
|
@@ -5,13 +5,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ServerCoin = void 0;
|
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
-
const datalayer_driver_1 = require("datalayer-driver");
|
|
8
|
+
const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
|
|
9
9
|
const FullNodePeer_1 = require("./FullNodePeer");
|
|
10
10
|
const coins_1 = require("./coins");
|
|
11
11
|
const Wallet_1 = require("./Wallet");
|
|
12
12
|
const NconfManager_1 = require("../utils/NconfManager");
|
|
13
13
|
const DataStore_1 = require("./DataStore");
|
|
14
|
+
const node_cache_1 = __importDefault(require("node-cache"));
|
|
14
15
|
const serverCoinCollateral = 300000000;
|
|
16
|
+
// Initialize the cache with a TTL of 300 seconds (5 minutes)
|
|
17
|
+
const serverCoinPeersCache = new node_cache_1.default({ stdTTL: 300 });
|
|
15
18
|
class ServerCoin {
|
|
16
19
|
constructor(storeId) {
|
|
17
20
|
this.storeId = storeId;
|
|
@@ -23,7 +26,7 @@ class ServerCoin {
|
|
|
23
26
|
const wallet = await Wallet_1.Wallet.load("default");
|
|
24
27
|
const publicSyntheticKey = await wallet.getPublicSyntheticKey();
|
|
25
28
|
const serverCoinCreationCoins = await (0, coins_1.selectUnspentCoins)(peer, BigInt(serverCoinCollateral), BigInt(1000000));
|
|
26
|
-
const currentEpoch = ServerCoin.getCurrentEpoch();
|
|
29
|
+
const { epoch: currentEpoch } = ServerCoin.getCurrentEpoch();
|
|
27
30
|
const epochBasedHint = (0, datalayer_driver_1.morphLauncherId)(Buffer.from(this.storeId, "hex"), BigInt(currentEpoch));
|
|
28
31
|
const newServerCoin = (0, datalayer_driver_1.createServerCoin)(publicSyntheticKey, serverCoinCreationCoins, epochBasedHint, [peerIp], BigInt(serverCoinCollateral), BigInt(1000000));
|
|
29
32
|
const combinedCoinSpends = [...newServerCoin.coinSpends];
|
|
@@ -94,13 +97,13 @@ class ServerCoin {
|
|
|
94
97
|
serverCoins = serverCoins.filter((coin) => coin.coin.parentCoinInfo !== serverCoin.parentCoinInfo);
|
|
95
98
|
await ServerCoin.serverCoinManager.setConfigValue(`${this.storeId}:${peerIp}`, serverCoins);
|
|
96
99
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
async getAllEpochPeers(epoch, blacklist = []) {
|
|
101
|
+
const cacheKey = `serverCoinPeers-${this.storeId}-${epoch}`;
|
|
102
|
+
// Check if the result is already cached
|
|
103
|
+
const cachedPeers = serverCoinPeersCache.get(cacheKey);
|
|
104
|
+
if (cachedPeers) {
|
|
105
|
+
return cachedPeers;
|
|
106
|
+
}
|
|
104
107
|
const epochBasedHint = (0, datalayer_driver_1.morphLauncherId)(Buffer.from(this.storeId, "hex"), BigInt(epoch));
|
|
105
108
|
const peer = await FullNodePeer_1.FullNodePeer.connect();
|
|
106
109
|
const maxClvmCost = BigInt(11000000000);
|
|
@@ -118,18 +121,37 @@ class ServerCoin {
|
|
|
118
121
|
if (process.env.DIG_DEBUG === "1") {
|
|
119
122
|
console.log("Server Coin Peers: ", serverCoinPeers);
|
|
120
123
|
}
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
const peerList = Array.from(serverCoinPeers);
|
|
125
|
+
// Cache the result
|
|
126
|
+
serverCoinPeersCache.set(cacheKey, peerList);
|
|
127
|
+
return peerList;
|
|
128
|
+
}
|
|
129
|
+
async getActiveEpochPeers(blacklist = []) {
|
|
130
|
+
const { epoch } = ServerCoin.getCurrentEpoch();
|
|
131
|
+
return this.getAllEpochPeers(epoch, blacklist);
|
|
132
|
+
}
|
|
133
|
+
// Sample server coins for the current epoch
|
|
134
|
+
async sampleCurrentEpoch(sampleSize = 5, blacklist = []) {
|
|
135
|
+
const { epoch } = ServerCoin.getCurrentEpoch();
|
|
136
|
+
return this.sampleServerCoinsByEpoch(epoch, sampleSize, blacklist);
|
|
137
|
+
}
|
|
138
|
+
// Sample server coins by epoch
|
|
139
|
+
async sampleServerCoinsByEpoch(epoch, sampleSize = 5, blacklist = []) {
|
|
140
|
+
const serverCoinPeers = await this.getAllEpochPeers(epoch, blacklist);
|
|
141
|
+
if (process.env.DIG_DEBUG === "1") {
|
|
142
|
+
console.log("Server Coin Peers: ", serverCoinPeers);
|
|
143
|
+
}
|
|
144
|
+
return lodash_1.default.sampleSize(serverCoinPeers, sampleSize);
|
|
123
145
|
}
|
|
124
146
|
// Get the current epoch based on the current timestamp
|
|
125
147
|
static getCurrentEpoch() {
|
|
126
|
-
return ServerCoin.
|
|
148
|
+
return ServerCoin.calculateEpochAndRound(new Date());
|
|
127
149
|
}
|
|
128
150
|
// Ensure server coin exists for the current epoch
|
|
129
151
|
async ensureServerCoinExists(peerIp) {
|
|
130
152
|
try {
|
|
131
153
|
console.log(`Ensuring server coin exists for store ${this.storeId}...`);
|
|
132
|
-
const currentEpoch = ServerCoin.getCurrentEpoch();
|
|
154
|
+
const { epoch: currentEpoch } = ServerCoin.getCurrentEpoch();
|
|
133
155
|
const serverCoins = await this.getServerCoinsForStore(peerIp);
|
|
134
156
|
// Check if a server coin already exists for the current epoch
|
|
135
157
|
const existingCoin = serverCoins.find((coin) => coin.epoch === currentEpoch);
|
|
@@ -160,7 +182,7 @@ class ServerCoin {
|
|
|
160
182
|
// Melt outdated server coins
|
|
161
183
|
async meltOutdatedEpochs(peerIp) {
|
|
162
184
|
try {
|
|
163
|
-
const currentEpoch = ServerCoin.getCurrentEpoch();
|
|
185
|
+
const { epoch: currentEpoch } = ServerCoin.getCurrentEpoch();
|
|
164
186
|
let serverCoins = await this.getServerCoinsForStore(peerIp);
|
|
165
187
|
// Filter out coins that are not in the current epoch
|
|
166
188
|
const outdatedCoins = serverCoins.filter((coin) => coin.epoch < currentEpoch);
|
|
@@ -244,17 +266,23 @@ class ServerCoin {
|
|
|
244
266
|
}
|
|
245
267
|
}
|
|
246
268
|
// Static method to calculate the current epoch
|
|
247
|
-
static
|
|
269
|
+
static calculateEpochAndRound(currentTimestampUTC) {
|
|
248
270
|
const firstEpochStart = new Date(Date.UTC(2024, 8, 3, 0, 0)); // Sept 3, 2024, 00:00 UTC
|
|
249
271
|
// Convert the current timestamp to milliseconds
|
|
250
272
|
const currentTimestampMillis = currentTimestampUTC.getTime();
|
|
251
273
|
// Calculate the number of milliseconds in one epoch (7 days)
|
|
252
|
-
const millisecondsInEpoch = 7 * 24 * 60 * 60 * 1000;
|
|
274
|
+
const millisecondsInEpoch = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
|
|
253
275
|
// Calculate the difference in milliseconds between the current timestamp and the first epoch start
|
|
254
276
|
const differenceMillis = currentTimestampMillis - firstEpochStart.getTime();
|
|
255
277
|
// Calculate the current epoch number
|
|
256
278
|
const epochNumber = Math.floor(differenceMillis / millisecondsInEpoch) + 1;
|
|
257
|
-
|
|
279
|
+
// Calculate the milliseconds elapsed since the start of the current epoch
|
|
280
|
+
const elapsedMillisInCurrentEpoch = differenceMillis % millisecondsInEpoch;
|
|
281
|
+
// Calculate the number of milliseconds in a round (10 minutes)
|
|
282
|
+
const millisecondsInRound = 10 * 60 * 1000; // 10 minutes in milliseconds
|
|
283
|
+
// Calculate the current round number
|
|
284
|
+
const roundNumber = Math.floor(elapsedMillisInCurrentEpoch / millisecondsInRound) + 1;
|
|
285
|
+
return { epoch: epochNumber, round: roundNumber };
|
|
258
286
|
}
|
|
259
287
|
}
|
|
260
288
|
exports.ServerCoin = ServerCoin;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from "buffer";
|
|
2
|
-
import { Peer, Coin, CoinSpend } from "datalayer-driver";
|
|
2
|
+
import { Peer, Coin, CoinSpend } from "@dignetwork/datalayer-driver";
|
|
3
3
|
export declare const DEFAULT_FEE_COIN_COST = 64000000;
|
|
4
4
|
export declare class Wallet {
|
|
5
5
|
private mnemonic;
|
|
@@ -20,7 +20,7 @@ export declare class Wallet {
|
|
|
20
20
|
private static getWalletFromKeyring;
|
|
21
21
|
private static saveWalletToKeyring;
|
|
22
22
|
createKeyOwnershipSignature(nonce: string): Promise<string>;
|
|
23
|
-
verifyKeyOwnershipSignature(nonce: string, signature: string, publicKey: string): Promise<boolean>;
|
|
23
|
+
static verifyKeyOwnershipSignature(nonce: string, signature: string, publicKey: string): Promise<boolean>;
|
|
24
24
|
selectUnspentCoins(peer: Peer, coinAmount: bigint, feeBigInt: bigint, omitCoins?: Coin[]): Promise<Coin[]>;
|
|
25
25
|
static calculateFeeForCoinSpends(peer: Peer, coinSpends: CoinSpend[] | null): Promise<bigint>;
|
|
26
26
|
static isCoinSpendable(peer: Peer, coinId: Buffer): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Wallet.d.ts","sourceRoot":"","sources":["../../src/blockchain/Wallet.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EASL,IAAI,EACJ,IAAI,EAEJ,SAAS,EAEV,MAAM,
|
|
1
|
+
{"version":3,"file":"Wallet.d.ts","sourceRoot":"","sources":["../../src/blockchain/Wallet.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EASL,IAAI,EACJ,IAAI,EAEJ,SAAS,EAEV,MAAM,8BAA8B,CAAC;AAMtC,eAAO,MAAM,qBAAqB,WAAa,CAAC;AAOhD,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO;WAKa,IAAI,CACtB,UAAU,GAAE,MAAkB,EAC9B,iBAAiB,GAAE,OAAc,GAChC,OAAO,CAAC,MAAM,CAAC;IAsBX,WAAW,IAAI,MAAM;WAOR,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAMpD,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAShE,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BhE,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;IAKrC,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;IAMxC,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IAKzC,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;IAMrC,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;WAK7B,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WASlD,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;mBAU/B,oBAAoB;mBAWpB,mBAAmB;IAM3B,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAOpD,2BAA2B,CAC7C,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IASN,kBAAkB,CAC7B,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,IAAI,EAAO,GACrB,OAAO,CAAC,IAAI,EAAE,CAAC;WAwCE,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;WAItF,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAOlF"}
|
|
@@ -38,7 +38,7 @@ const chia_root_resolver_1 = require("chia-root-resolver");
|
|
|
38
38
|
const chia_config_loader_1 = require("chia-config-loader");
|
|
39
39
|
const encryption_1 = require("../utils/encryption");
|
|
40
40
|
const buffer_1 = require("buffer");
|
|
41
|
-
const datalayer_driver_1 = require("datalayer-driver");
|
|
41
|
+
const datalayer_driver_1 = require("@dignetwork/datalayer-driver");
|
|
42
42
|
const config_1 = require("../utils/config");
|
|
43
43
|
const FileCache_1 = require("../utils/FileCache");
|
|
44
44
|
const KEYRING_FILE = "keyring.json";
|
|
@@ -174,7 +174,7 @@ class Wallet {
|
|
|
174
174
|
const signature = (0, datalayer_driver_1.signMessage)(buffer_1.Buffer.from(message, "utf-8"), privateSyntheticKey);
|
|
175
175
|
return signature.toString("hex");
|
|
176
176
|
}
|
|
177
|
-
async verifyKeyOwnershipSignature(nonce, signature, publicKey) {
|
|
177
|
+
static async verifyKeyOwnershipSignature(nonce, signature, publicKey) {
|
|
178
178
|
const message = `Signing this message to prove ownership of key.\n\nNonce: ${nonce}`;
|
|
179
179
|
return (0, datalayer_driver_1.verifySignedMessage)(buffer_1.Buffer.from(signature, "hex"), buffer_1.Buffer.from(publicKey, "hex"), buffer_1.Buffer.from(message, "utf-8"));
|
|
180
180
|
}
|