Skip to content

Commit 3a49aad

Browse files
Merge pull request #97 from DIG-Network/release/v0.0.1-alpha.107
Release/v0.0.1 alpha.107
2 parents fa7bfb1 + 3b78c51 commit 3a49aad

File tree

8 files changed

+220
-94
lines changed

8 files changed

+220
-94
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
44

5+
### [0.0.1-alpha.107](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.106...v0.0.1-alpha.107) (2024-10-01)
6+
7+
8+
### Features
9+
10+
* add store info precache ([27b11e4](https://github.com/DIG-Network/dig-chia-sdk/commit/27b11e4e9334cb7fe318685e06bb7c0ec980dca2))
11+
512
### [0.0.1-alpha.106](https://github.com/DIG-Network/dig-chia-sdk/compare/v0.0.1-alpha.105...v0.0.1-alpha.106) (2024-10-01)
613

714

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dignetwork/dig-sdk",
3-
"version": "0.0.1-alpha.106",
3+
"version": "0.0.1-alpha.107",
44
"description": "",
55
"type": "commonjs",
66
"main": "./dist/index.js",

src/DigNetwork/PropagationServer.ts

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import https from "https";
77
import os from "os";
88
import path from "path";
99
import ProgressStream from "progress-stream";
10+
import * as zlib from "zlib";
1011

11-
import { asyncPool } from "../utils/asyncPool";
12+
import { asyncPool } from "../utils/promiseUtils";
1213
import { createSpinner } from "nanospinner";
1314
import { getFilePathFromSha256 } from "../utils/hashUtils";
1415
import { getOrCreateSSLCerts } from "../utils/ssl";
@@ -18,7 +19,7 @@ import { PassThrough } from "stream";
1819
import { promptCredentials } from "../utils/credentialsUtils";
1920
import { STORE_PATH } from "../utils/config";
2021
import { Wallet, DataStore } from "../blockchain";
21-
import { formatHost } from '../utils/network';
22+
import { formatHost } from "../utils/network";
2223

2324
// Helper function to trim long filenames with ellipsis and ensure consistent padding
2425
function formatFilename(filename: string | undefined, maxLength = 30): string {
@@ -121,7 +122,9 @@ export class PropagationServer {
121122
httpsAgent: this.createHttpsAgent(),
122123
};
123124

124-
let url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/${this.storeId}`;
125+
let url = `https://${formatHost(this.ipAddress)}:${
126+
PropagationServer.port
127+
}/${this.storeId}`;
125128
if (rootHash) {
126129
url += `?hasRootHash=${rootHash}`;
127130
}
@@ -194,7 +197,9 @@ export class PropagationServer {
194197
};
195198
}
196199

197-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/upload/${this.storeId}?roothash=${rootHash}`;
200+
const url = `https://${formatHost(this.ipAddress)}:${
201+
PropagationServer.port
202+
}/upload/${this.storeId}?roothash=${rootHash}`;
198203
const response = await axios.post(url, formData, config);
199204

200205
this.sessionId = response.data.sessionId;
@@ -223,7 +228,9 @@ export class PropagationServer {
223228
httpsAgent: this.createHttpsAgent(),
224229
};
225230

226-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/upload/${this.storeId}/${this.sessionId}/${filename}`;
231+
const url = `https://${formatHost(this.ipAddress)}:${
232+
PropagationServer.port
233+
}/upload/${this.storeId}/${this.sessionId}/${filename}`;
227234
const response = await axios.head(url, config);
228235

229236
// Check for 'x-file-exists' header
@@ -246,7 +253,7 @@ export class PropagationServer {
246253
* Upload a file to the server by sending a PUT request.
247254
* Logs progress using a local cli-progress bar.
248255
*/
249-
async uploadFile(label: string, dataPath: string) {
256+
async uploadFile(label: string, dataPath: string, uncompress: boolean = false) {
250257
const filePath = path.join(STORE_PATH, this.storeId, dataPath);
251258

252259
const { nonce, fileExists } = await this.getFileNonce(dataPath);
@@ -306,8 +313,20 @@ export class PropagationServer {
306313
PropagationServer.inactivityTimeout
307314
);
308315

309-
// Pipe the read stream through the progress stream into the PassThrough stream
310-
fileReadStream.pipe(progressStream).pipe(passThroughStream);
316+
// Decide whether to uncompress the file during upload
317+
if (uncompress) {
318+
// Create a gunzip (uncompression) stream
319+
const gunzip = zlib.createGunzip();
320+
321+
// Pipe the streams: fileReadStream -> gunzip -> progressStream -> passThroughStream
322+
fileReadStream
323+
.pipe(gunzip)
324+
.pipe(progressStream)
325+
.pipe(passThroughStream);
326+
} else {
327+
// Pipe the streams: fileReadStream -> progressStream -> passThroughStream
328+
fileReadStream.pipe(progressStream).pipe(passThroughStream);
329+
}
311330

312331
// Use form-data to construct the request body
313332
const formData = new FormData();
@@ -327,7 +346,9 @@ export class PropagationServer {
327346
maxBodyLength: Infinity,
328347
};
329348

330-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/upload/${this.storeId}/${this.sessionId}/${dataPath}`;
349+
const url = `https://${formatHost(this.ipAddress)}:${
350+
PropagationServer.port
351+
}/upload/${this.storeId}/${this.sessionId}/${dataPath}`;
331352

332353
// Create a promise that resolves when the progress stream ends
333354
const progressPromise = new Promise<void>((resolve, reject) => {
@@ -369,7 +390,9 @@ export class PropagationServer {
369390
: undefined,
370391
};
371392

372-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/commit/${this.storeId}/${this.sessionId}`;
393+
const url = `https://${formatHost(this.ipAddress)}:${
394+
PropagationServer.port
395+
}/commit/${this.storeId}/${this.sessionId}`;
373396
const response = await axios.post(url, {}, config);
374397

375398
spinner.success({
@@ -424,8 +447,7 @@ export class PropagationServer {
424447
await propagationServer.startUploadSession(rootHash);
425448

426449
const dataStore = DataStore.from(storeId);
427-
const files = await dataStore.getFileSetForRootHash(rootHash);
428-
450+
const files = await dataStore.getFileSetForRootHash(rootHash, true);
429451
// Prepare upload tasks
430452
const uploadTasks = files.map((file) => ({
431453
label: file.name,
@@ -436,7 +458,7 @@ export class PropagationServer {
436458
const concurrencyLimit = 10; // Adjust this number as needed
437459

438460
await asyncPool(concurrencyLimit, uploadTasks, async (task) => {
439-
await propagationServer.uploadFile(task.label, task.dataPath);
461+
await propagationServer.uploadFile(task.label, task.dataPath, true);
440462
});
441463

442464
// Commit the session after all files have been uploaded
@@ -454,7 +476,9 @@ export class PropagationServer {
454476
* Logs progress using a local cli-progress bar.
455477
*/
456478
async fetchFile(dataPath: string): Promise<Buffer> {
457-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/fetch/${this.storeId}/${dataPath}`;
479+
const url = `https://${formatHost(this.ipAddress)}:${
480+
PropagationServer.port
481+
}/fetch/${this.storeId}/${dataPath}`;
458482
const config: AxiosRequestConfig = {
459483
responseType: "stream",
460484
httpsAgent: this.createHttpsAgent(),
@@ -545,7 +569,9 @@ export class PropagationServer {
545569
httpsAgent: this.createHttpsAgent(),
546570
};
547571

548-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/store/${this.storeId}/${rootHash}/${dataPath}`;
572+
const url = `https://${formatHost(this.ipAddress)}:${
573+
PropagationServer.port
574+
}/store/${this.storeId}/${rootHash}/${dataPath}`;
549575
const response = await axios.head(url, config);
550576

551577
// Check the headers for file existence and size
@@ -575,7 +601,9 @@ export class PropagationServer {
575601
rootHash: string,
576602
baseDir: string
577603
) {
578-
const url = `https://${formatHost(this.ipAddress)}:${PropagationServer.port}/fetch/${this.storeId}/${dataPath}`;
604+
const url = `https://${formatHost(this.ipAddress)}:${
605+
PropagationServer.port
606+
}/fetch/${this.storeId}/${dataPath}`;
579607
let downloadPath = path.join(baseDir, dataPath);
580608

581609
// Ensure that the directory for the file exists

src/blockchain/DataStore.ts

Lines changed: 41 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { FileCache } from "../utils/FileCache";
3737
import { DataStoreSerializer } from "./DataStoreSerializer";
3838
import NodeCache from "node-cache";
3939
import { MAIN_NET_GENISES_CHALLENGE } from "../utils/config";
40+
import { StoreInfoCacheUpdater } from "./StoreInfoCacheUpdater";
4041

4142
// Initialize the cache with a TTL of 180 seconds (3 minutes)
4243
const rootHistoryCache = new NodeCache({ stdTTL: 180 });
@@ -311,77 +312,39 @@ export class DataStore {
311312
latestHash: Buffer;
312313
}> {
313314
try {
315+
// Kick off the updater instance in the backgounf if not already running
316+
StoreInfoCacheUpdater.initInstance();
317+
314318
// Initialize the cache for the current storeId's coin info
315319
const storeCoinCache = new FileCache<{
316320
latestStore: ReturnType<DataStoreSerializer["serialize"]>;
317321
latestHeight: number;
318322
latestHash: string;
319323
}>(`stores`);
320-
324+
321325
// Try to get cached store info
322326
const cachedInfo = storeCoinCache.get(this.storeId);
323-
327+
324328
if (cachedInfo) {
325-
try {
326-
const {
327-
latestStore: serializedStore,
328-
latestHeight: previousHeight,
329-
latestHash: previousHash,
330-
} = cachedInfo;
331-
332-
// Deserialize the stored data using DataStoreSerializer
333-
const { latestStore: previousInfo } = DataStoreSerializer.deserialize(
334-
{
335-
latestStore: serializedStore,
336-
latestHeight: previousHeight.toString(),
337-
latestHash: previousHash,
338-
}
339-
);
340-
341-
// Sync with peer if necessary
342-
const peer = await FullNodePeer.connect();
343-
const { latestStore, latestHeight } = await peer.syncStore(
344-
previousInfo,
345-
previousHeight,
346-
Buffer.from(previousHash, "hex"),
347-
false
348-
);
349-
const latestHash = await peer.getHeaderHash(latestHeight);
350-
351-
// Serialize the store data for caching
352-
const serializedLatestStore = new DataStoreSerializer(
353-
latestStore,
354-
latestHeight,
355-
latestHash
356-
).serialize();
357-
358-
// Cache updated store info
359-
storeCoinCache.set(this.storeId, {
360-
latestStore: serializedLatestStore,
361-
latestHeight,
362-
latestHash: latestHash.toString("hex"),
329+
// If we have cached info, return it directly
330+
const { latestStore, latestHeight } =
331+
DataStoreSerializer.deserialize({
332+
latestStore: cachedInfo.latestStore,
333+
latestHeight: cachedInfo.latestHeight.toString(),
334+
latestHash: cachedInfo.latestHash,
363335
});
364-
365-
return { latestStore, latestHeight, latestHash };
366-
} catch {
367-
// Return cached info if sync fails
368-
const { latestStore, latestHeight, latestHash } =
369-
DataStoreSerializer.deserialize({
370-
latestStore: cachedInfo.latestStore,
371-
latestHeight: cachedInfo.latestHeight.toString(),
372-
latestHash: cachedInfo.latestHash,
373-
});
374-
return {
375-
latestStore,
376-
latestHeight,
377-
latestHash: latestHash,
378-
};
379-
}
336+
337+
return {
338+
latestStore,
339+
latestHeight: cachedInfo.latestHeight,
340+
latestHash: Buffer.from(cachedInfo.latestHash, "hex"),
341+
};
380342
}
381-
343+
344+
// If no cached info, proceed to fetch and cache it
382345
// Use getCreationHeight to retrieve height and hash information
383346
const { createdAtHeight, createdAtHash } = await this.getCreationHeight();
384-
347+
385348
// Sync store from peer
386349
const peer = await FullNodePeer.connect();
387350
const { latestStore, latestHeight } = await peer.syncStoreFromLauncherId(
@@ -390,29 +353,29 @@ export class DataStore {
390353
createdAtHash,
391354
false
392355
);
393-
356+
394357
const latestHash = await peer.getHeaderHash(latestHeight);
395-
358+
396359
// Serialize the latest store info for caching
397360
const serializedLatestStore = new DataStoreSerializer(
398361
latestStore,
399362
latestHeight,
400363
latestHash
401364
).serialize();
402-
365+
403366
// Cache the latest store info
404367
storeCoinCache.set(this.storeId, {
405368
latestStore: serializedLatestStore,
406369
latestHeight,
407370
latestHash: latestHash.toString("hex"),
408371
});
409-
372+
410373
return { latestStore, latestHeight, latestHash };
411374
} catch (error) {
412375
console.trace("Failed to fetch coin info", error);
413376
throw error;
414377
}
415-
}
378+
}
416379

417380
public async cacheStoreCreationHeight(): Promise<{
418381
createdAtHeight: number;
@@ -621,7 +584,8 @@ export class DataStore {
621584
* @returns {Promise<{ fileName: string, file: string }[]>} - An array of unique file objects.
622585
*/
623586
public async getFileSetForRootHash(
624-
rootHash: string
587+
rootHash: string,
588+
skipIntegirtyCheck: boolean = false
625589
): Promise<{ name: string; path: string }[]> {
626590
const datFilePath = path.join(STORE_PATH, this.storeId, `${rootHash}.dat`);
627591
const datFileContent = JSON.parse(fs.readFileSync(datFilePath, "utf-8"));
@@ -637,16 +601,20 @@ export class DataStore {
637601
);
638602

639603
// Perform the integrity check
640-
const integrityCheck =
641-
await DataIntegrityTree.validateKeyIntegrityWithForeignTree(
642-
fileKey,
643-
datFileContent.files[fileKey].sha256,
644-
datFileContent,
645-
rootHash,
646-
path.join(STORE_PATH, this.storeId, "data")
647-
);
604+
let integrityCheck;
605+
606+
if (!skipIntegirtyCheck) {
607+
integrityCheck =
608+
await DataIntegrityTree.validateKeyIntegrityWithForeignTree(
609+
fileKey,
610+
datFileContent.files[fileKey].sha256,
611+
datFileContent,
612+
rootHash,
613+
path.join(STORE_PATH, this.storeId, "data")
614+
);
615+
}
648616

649-
if (integrityCheck) {
617+
if (integrityCheck || skipIntegirtyCheck) {
650618
// Add the file to the Set
651619
filesInvolved.add({
652620
name: Buffer.from(fileKey, "hex").toString("utf-8"),

0 commit comments

Comments
 (0)