@bsv/wallet-toolbox 1.6.14 → 1.6.16
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/docs/client.md +123 -93
- package/docs/services.md +123 -93
- package/docs/wallet.md +123 -93
- package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts +1 -0
- package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts.map +1 -1
- package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.js +125 -109
- package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
- package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts +16 -4
- package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
- package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +65 -45
- package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
- package/mobile/package-lock.json +2 -2
- package/mobile/package.json +1 -1
- package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts +1 -0
- package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Chaintracks.js +125 -109
- package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts +16 -4
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +65 -45
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/services/chaintracker/chaintracks/Chaintracks.ts +124 -109
- package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +75 -50
package/docs/wallet.md
CHANGED
|
@@ -8515,10 +8515,15 @@ export class BulkFileDataManager {
|
|
|
8515
8515
|
readonly maxRetained?: number;
|
|
8516
8516
|
readonly fromKnownSourceUrl?: string;
|
|
8517
8517
|
constructor(options: BulkFileDataManagerOptions | Chain)
|
|
8518
|
+
async deleteBulkFiles(): Promise<void>
|
|
8519
|
+
async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
|
|
8520
|
+
heightRangesFromBulkFiles(files: BulkHeaderFileInfo[]): {
|
|
8521
|
+
all: HeightRange;
|
|
8522
|
+
cdn: HeightRange;
|
|
8523
|
+
incremental: HeightRange;
|
|
8524
|
+
}
|
|
8518
8525
|
async createReader(range?: HeightRange, maxBufferSize?: number): Promise<BulkFileDataReader>
|
|
8519
8526
|
async updateFromUrl(cdnUrl: string): Promise<void>
|
|
8520
|
-
async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
|
|
8521
|
-
async deleteBulkFiles(): Promise<void>
|
|
8522
8527
|
async merge(files: BulkHeaderFileInfo[]): Promise<BulkFileDataManagerMergeResult>
|
|
8523
8528
|
toLogString(what?: BulkFileDataManagerMergeResult | BulkFileData[] | BulkHeaderFileInfo[]): string
|
|
8524
8529
|
async mergeIncrementalBlockHeaders(newBulkHeaders: BlockHeader[], incrementalChainWork?: string): Promise<void>
|
|
@@ -8535,6 +8540,19 @@ export class BulkFileDataManager {
|
|
|
8535
8540
|
|
|
8536
8541
|
See also: [BlockHeader](./client.md#interface-blockheader), [BulkFileDataManagerMergeResult](./services.md#interface-bulkfiledatamanagermergeresult), [BulkFileDataManagerOptions](./services.md#interface-bulkfiledatamanageroptions), [BulkFileDataReader](./services.md#class-bulkfiledatareader), [BulkHeaderFileInfo](./services.md#interface-bulkheaderfileinfo), [Chain](./client.md#type-chain), [ChaintracksFetchApi](./services.md#interface-chaintracksfetchapi), [ChaintracksFsApi](./services.md#interface-chaintracksfsapi), [ChaintracksStorageBulkFileApi](./services.md#interface-chaintracksstoragebulkfileapi), [HeightRange](./services.md#class-heightrange)
|
|
8537
8542
|
|
|
8543
|
+
###### Method setStorage
|
|
8544
|
+
|
|
8545
|
+
If `bfds` are going to be backed by persistent storage,
|
|
8546
|
+
must be called before making storage available.
|
|
8547
|
+
|
|
8548
|
+
Synchronizes bfds and storage files, after which this manager maintains sync.
|
|
8549
|
+
There should be no changes to bulk files by direct access to storage bulk file methods.
|
|
8550
|
+
|
|
8551
|
+
```ts
|
|
8552
|
+
async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
|
|
8553
|
+
```
|
|
8554
|
+
See also: [ChaintracksStorageBulkFileApi](./services.md#interface-chaintracksstoragebulkfileapi)
|
|
8555
|
+
|
|
8538
8556
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
8539
8557
|
|
|
8540
8558
|
---
|
|
@@ -9403,130 +9421,142 @@ export class Chaintracks implements ChaintracksManagementApi {
|
|
|
9403
9421
|
const cdnSyncRepeatMsecs = 24 * 60 * 60 * 1000;
|
|
9404
9422
|
const syncCheckRepeatMsecs = 30 * 60 * 1000;
|
|
9405
9423
|
while (!this.stopMainThread) {
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
skipBulkSync
|
|
9413
|
-
|
|
9414
|
-
|
|
9424
|
+
try {
|
|
9425
|
+
const now = Date.now();
|
|
9426
|
+
lastSyncCheck = now;
|
|
9427
|
+
const presentHeight = await this.getPresentHeight();
|
|
9428
|
+
const before = await this.storage.getAvailableHeightRanges();
|
|
9429
|
+
let skipBulkSync = !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2;
|
|
9430
|
+
if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
|
|
9431
|
+
skipBulkSync = false;
|
|
9432
|
+
}
|
|
9433
|
+
this.log(`Chaintracks Update Services: Bulk Header Sync Review
|
|
9415
9434
|
presentHeight=${presentHeight} addLiveRecursionLimit=${this.addLiveRecursionLimit}
|
|
9416
9435
|
Before synchronize: bulk ${before.bulk}, live ${before.live}
|
|
9417
9436
|
${skipBulkSync ? "Skipping" : "Starting"} syncBulkStorage.
|
|
9418
9437
|
`);
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
needSyncCheck = true;
|
|
9438
|
-
}
|
|
9439
|
-
else if (ihr.noPrev) {
|
|
9440
|
-
if (recursions-- <= 0) {
|
|
9441
|
-
this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
|
|
9438
|
+
if (!skipBulkSync) {
|
|
9439
|
+
lastBulkSync = now;
|
|
9440
|
+
if (this.available)
|
|
9441
|
+
await this.syncBulkStorage(presentHeight, before);
|
|
9442
|
+
else
|
|
9443
|
+
await this.syncBulkStorageNoLock(presentHeight, before);
|
|
9444
|
+
}
|
|
9445
|
+
let count = 0;
|
|
9446
|
+
let liveHeaderDupes = 0;
|
|
9447
|
+
let needSyncCheck = false;
|
|
9448
|
+
for (; !needSyncCheck && !this.stopMainThread;) {
|
|
9449
|
+
let header = this.liveHeaders.shift();
|
|
9450
|
+
if (header) {
|
|
9451
|
+
let recursions = this.addLiveRecursionLimit;
|
|
9452
|
+
for (; !needSyncCheck && !this.stopMainThread;) {
|
|
9453
|
+
const ihr = await this.addLiveHeader(header);
|
|
9454
|
+
if (this.invalidInsertHeaderResult(ihr)) {
|
|
9455
|
+
this.log(`Ignoring liveHeader ${header.height} ${header.hash} due to invalid insert result.`);
|
|
9442
9456
|
needSyncCheck = true;
|
|
9443
9457
|
}
|
|
9444
|
-
else {
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
if (!prevHeader) {
|
|
9448
|
-
this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${asString(hash)}`);
|
|
9458
|
+
else if (ihr.noPrev) {
|
|
9459
|
+
if (recursions-- <= 0) {
|
|
9460
|
+
this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
|
|
9449
9461
|
needSyncCheck = true;
|
|
9450
9462
|
}
|
|
9451
9463
|
else {
|
|
9452
|
-
|
|
9453
|
-
|
|
9464
|
+
const hash = header.previousHash;
|
|
9465
|
+
const prevHeader = await this.getMissingBlockHeader(hash);
|
|
9466
|
+
if (!prevHeader) {
|
|
9467
|
+
this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${asString(hash)}`);
|
|
9468
|
+
needSyncCheck = true;
|
|
9469
|
+
}
|
|
9470
|
+
else {
|
|
9471
|
+
this.liveHeaders.unshift(header);
|
|
9472
|
+
header = prevHeader;
|
|
9473
|
+
}
|
|
9454
9474
|
}
|
|
9455
9475
|
}
|
|
9456
|
-
}
|
|
9457
|
-
else {
|
|
9458
|
-
if (this.subscriberCallbacksEnabled)
|
|
9459
|
-
this.log(`addLiveHeader ${header.height}${ihr.added ? " added" : ""}${ihr.dupe ? " dupe" : ""}${ihr.isActiveTip ? " isActiveTip" : ""}${ihr.reorgDepth ? " reorg depth " + ihr.reorgDepth : ""}${ihr.noPrev ? " noPrev" : ""}${ihr.noActiveAncestor || ihr.noTip || ihr.badPrev ? " error" : ""}`);
|
|
9460
|
-
if (ihr.dupe) {
|
|
9461
|
-
liveHeaderDupes++;
|
|
9462
|
-
}
|
|
9463
|
-
if (ihr.added) {
|
|
9464
|
-
count++;
|
|
9465
|
-
}
|
|
9466
|
-
break;
|
|
9467
|
-
}
|
|
9468
|
-
}
|
|
9469
|
-
}
|
|
9470
|
-
else {
|
|
9471
|
-
const bheader = this.baseHeaders.shift();
|
|
9472
|
-
if (bheader) {
|
|
9473
|
-
const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
|
|
9474
|
-
if (!prev) {
|
|
9475
|
-
this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
|
|
9476
|
-
}
|
|
9477
|
-
else {
|
|
9478
|
-
const header: BlockHeader = {
|
|
9479
|
-
...bheader,
|
|
9480
|
-
height: prev.height + 1,
|
|
9481
|
-
hash: blockHash(bheader)
|
|
9482
|
-
};
|
|
9483
|
-
const ihr = await this.addLiveHeader(header);
|
|
9484
|
-
if (this.invalidInsertHeaderResult(ihr)) {
|
|
9485
|
-
this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
|
|
9486
|
-
}
|
|
9487
9476
|
else {
|
|
9488
9477
|
if (this.subscriberCallbacksEnabled)
|
|
9489
|
-
this.log(`
|
|
9478
|
+
this.log(`addLiveHeader ${header.height}${ihr.added ? " added" : ""}${ihr.dupe ? " dupe" : ""}${ihr.isActiveTip ? " isActiveTip" : ""}${ihr.reorgDepth ? " reorg depth " + ihr.reorgDepth : ""}${ihr.noPrev ? " noPrev" : ""}${ihr.noActiveAncestor || ihr.noTip || ihr.badPrev ? " error" : ""}`);
|
|
9479
|
+
if (ihr.dupe) {
|
|
9480
|
+
liveHeaderDupes++;
|
|
9481
|
+
}
|
|
9490
9482
|
if (ihr.added) {
|
|
9491
9483
|
count++;
|
|
9492
9484
|
}
|
|
9485
|
+
break;
|
|
9493
9486
|
}
|
|
9494
9487
|
}
|
|
9495
9488
|
}
|
|
9496
9489
|
else {
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9490
|
+
const bheader = this.baseHeaders.shift();
|
|
9491
|
+
if (bheader) {
|
|
9492
|
+
const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
|
|
9493
|
+
if (!prev) {
|
|
9494
|
+
this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
|
|
9495
|
+
}
|
|
9496
|
+
else {
|
|
9497
|
+
const header: BlockHeader = {
|
|
9498
|
+
...bheader,
|
|
9499
|
+
height: prev.height + 1,
|
|
9500
|
+
hash: blockHash(bheader)
|
|
9501
|
+
};
|
|
9502
|
+
const ihr = await this.addLiveHeader(header);
|
|
9503
|
+
if (this.invalidInsertHeaderResult(ihr)) {
|
|
9504
|
+
this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
|
|
9505
|
+
}
|
|
9506
|
+
else {
|
|
9507
|
+
if (this.subscriberCallbacksEnabled)
|
|
9508
|
+
this.log(`addBaseHeader ${header.height}${ihr.added ? " added" : ""}${ihr.dupe ? " dupe" : ""}${ihr.isActiveTip ? " isActiveTip" : ""}${ihr.reorgDepth ? " reorg depth " + ihr.reorgDepth : ""}${ihr.noPrev ? " noPrev" : ""}${ihr.noActiveAncestor || ihr.noTip || ihr.badPrev ? " error" : ""}`);
|
|
9509
|
+
if (ihr.added) {
|
|
9510
|
+
count++;
|
|
9511
|
+
}
|
|
9512
|
+
}
|
|
9501
9513
|
}
|
|
9502
|
-
|
|
9503
|
-
|
|
9514
|
+
}
|
|
9515
|
+
else {
|
|
9516
|
+
if (count > 0) {
|
|
9517
|
+
if (liveHeaderDupes > 0) {
|
|
9518
|
+
this.log(`${liveHeaderDupes} duplicate headers ignored.`);
|
|
9519
|
+
liveHeaderDupes = 0;
|
|
9520
|
+
}
|
|
9521
|
+
const updated = await this.storage.getAvailableHeightRanges();
|
|
9522
|
+
this.log(`After adding ${count} live headers
|
|
9504
9523
|
After live: bulk ${updated.bulk}, live ${updated.live}
|
|
9505
9524
|
`);
|
|
9506
|
-
|
|
9507
|
-
}
|
|
9508
|
-
if (!this.subscriberCallbacksEnabled) {
|
|
9509
|
-
const live = await this.storage.findLiveHeightRange();
|
|
9510
|
-
if (!live.isEmpty) {
|
|
9511
|
-
this.subscriberCallbacksEnabled = true;
|
|
9512
|
-
this.log(`listening at height of ${live.maxHeight}`);
|
|
9525
|
+
count = 0;
|
|
9513
9526
|
}
|
|
9527
|
+
if (!this.subscriberCallbacksEnabled) {
|
|
9528
|
+
const live = await this.storage.findLiveHeightRange();
|
|
9529
|
+
if (!live.isEmpty) {
|
|
9530
|
+
this.subscriberCallbacksEnabled = true;
|
|
9531
|
+
this.log(`listening at height of ${live.maxHeight}`);
|
|
9532
|
+
}
|
|
9533
|
+
}
|
|
9534
|
+
if (!this.available) {
|
|
9535
|
+
this.available = true;
|
|
9536
|
+
}
|
|
9537
|
+
needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
|
|
9538
|
+
if (!needSyncCheck)
|
|
9539
|
+
await wait(1000);
|
|
9514
9540
|
}
|
|
9515
|
-
if (!this.available) {
|
|
9516
|
-
this.available = true;
|
|
9517
|
-
}
|
|
9518
|
-
needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
|
|
9519
|
-
if (!needSyncCheck)
|
|
9520
|
-
await wait(1000);
|
|
9521
9541
|
}
|
|
9522
9542
|
}
|
|
9523
9543
|
}
|
|
9544
|
+
catch (eu: unknown) {
|
|
9545
|
+
const e = WalletError.fromUnknown(eu);
|
|
9546
|
+
if (!this.available) {
|
|
9547
|
+
this.startupError = e;
|
|
9548
|
+
this.stopMainThread = true;
|
|
9549
|
+
}
|
|
9550
|
+
else {
|
|
9551
|
+
this.log(`Error occurred during chaintracks main thread processing: ${e.stack || e.message}`);
|
|
9552
|
+
}
|
|
9553
|
+
}
|
|
9524
9554
|
}
|
|
9525
9555
|
}
|
|
9526
9556
|
}
|
|
9527
9557
|
```
|
|
9528
9558
|
|
|
9529
|
-
See also: [BaseBlockHeader](./client.md#interface-baseblockheader), [BlockHeader](./client.md#interface-blockheader), [Chain](./client.md#type-chain), [ChaintracksFsApi](./services.md#interface-chaintracksfsapi), [ChaintracksInfoApi](./services.md#interface-chaintracksinfoapi), [ChaintracksManagementApi](./services.md#interface-chaintracksmanagementapi), [ChaintracksOptions](./services.md#interface-chaintracksoptions), [HeaderListener](./services.md#type-headerlistener), [HeightRange](./services.md#class-heightrange), [HeightRanges](./services.md#interface-heightranges), [LiveBlockHeader](./services.md#interface-liveblockheader), [ReorgListener](./services.md#type-reorglistener), [Services](./services.md#class-services), [asString](./client.md#function-asstring), [blockHash](./services.md#function-blockhash), [wait](./client.md#function-wait)
|
|
9559
|
+
See also: [BaseBlockHeader](./client.md#interface-baseblockheader), [BlockHeader](./client.md#interface-blockheader), [Chain](./client.md#type-chain), [ChaintracksFsApi](./services.md#interface-chaintracksfsapi), [ChaintracksInfoApi](./services.md#interface-chaintracksinfoapi), [ChaintracksManagementApi](./services.md#interface-chaintracksmanagementapi), [ChaintracksOptions](./services.md#interface-chaintracksoptions), [HeaderListener](./services.md#type-headerlistener), [HeightRange](./services.md#class-heightrange), [HeightRanges](./services.md#interface-heightranges), [LiveBlockHeader](./services.md#interface-liveblockheader), [ReorgListener](./services.md#type-reorglistener), [Services](./services.md#class-services), [WalletError](./client.md#class-walleterror), [asString](./client.md#function-asstring), [blockHash](./services.md#function-blockhash), [wait](./client.md#function-wait)
|
|
9530
9560
|
|
|
9531
9561
|
###### Method addHeader
|
|
9532
9562
|
|
|
@@ -18,6 +18,7 @@ export declare class Chaintracks implements ChaintracksManagementApi {
|
|
|
18
18
|
private liveHeaders;
|
|
19
19
|
private addLiveRecursionLimit;
|
|
20
20
|
private available;
|
|
21
|
+
private startupError;
|
|
21
22
|
private subscriberCallbacksEnabled;
|
|
22
23
|
private stopMainThread;
|
|
23
24
|
private lastPresentHeight;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chaintracks.d.ts","sourceRoot":"","sources":["../../../../../../src/services/chaintracker/chaintracks/Chaintracks.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAEnF,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC9F,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAIpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"Chaintracks.d.ts","sourceRoot":"","sources":["../../../../../../src/services/chaintracker/chaintracks/Chaintracks.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAEnF,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC9F,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAIpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAIzD,qBAAa,WAAY,YAAW,wBAAwB;IA2CvC,OAAO,EAAE,kBAAkB;IA1C9C,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAatD,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAW;IAExC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAG1B,OAAO,CAAC,QAAQ,CAAsB;IAEtC,OAAO,CAAC,SAAS,CAAoG;IACrH,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,aAAa,CAAmB;IAExC,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,qBAAqB,CAAK;IAElC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,YAAY,CAA2B;IAE/C,OAAO,CAAC,0BAA0B,CAAQ;IAC1C,OAAO,CAAC,cAAc,CAAO;IAE7B,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,sBAAsB,CAAI;IAClC,OAAO,CAAC,uBAAuB,CAAY;IAE3C,OAAO,CAAC,IAAI,CAAoC;gBAE7B,OAAO,EAAE,kBAAkB;IAoBxC,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC;IAIhC;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAqBnC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAIhC,gBAAgB,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAM3D,eAAe,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAMzD,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ3D;;;;;;;;OAQG;IACG,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD;;;;;;;;OAQG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB9B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBxB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAI1B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAMlC,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;YAK7D,yBAAyB;IAIjC,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;YAK9D,4BAA4B;IAIpC,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpE,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC;YAK9B,aAAa;IAcrB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK1D,kBAAkB,IAAI,OAAO,CAAC,WAAW,CAAC;IAK1C,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAKnC,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAM9E,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAK1E;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAY5B,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,gBAAgB,EACtB,SAAS,CAAC,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE,MAAM,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAMV,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;YAIvB,eAAe;YAIf,qBAAqB;YA6CrB,qBAAqB;IAQnC,OAAO,CAAC,yBAAyB;YAInB,aAAa;IAyC3B;;;;;;;;;;;OAWG;YACW,0BAA0B;CAmKzC"}
|
|
@@ -7,6 +7,7 @@ const utilityHelpers_noBuffer_1 = require("../../../utility/utilityHelpers.noBuf
|
|
|
7
7
|
const HeightRange_1 = require("./util/HeightRange");
|
|
8
8
|
const SingleWriterMultiReaderLock_1 = require("./util/SingleWriterMultiReaderLock");
|
|
9
9
|
const utilityHelpers_1 = require("../../../utility/utilityHelpers");
|
|
10
|
+
const WalletError_1 = require("../../../sdk/WalletError");
|
|
10
11
|
class Chaintracks {
|
|
11
12
|
static createOptions(chain) {
|
|
12
13
|
return {
|
|
@@ -30,6 +31,7 @@ class Chaintracks {
|
|
|
30
31
|
this.liveHeaders = [];
|
|
31
32
|
this.addLiveRecursionLimit = 11;
|
|
32
33
|
this.available = false;
|
|
34
|
+
this.startupError = null;
|
|
33
35
|
this.subscriberCallbacksEnabled = false;
|
|
34
36
|
this.stopMainThread = true;
|
|
35
37
|
this.lastPresentHeight = 0;
|
|
@@ -146,9 +148,11 @@ class Chaintracks {
|
|
|
146
148
|
// Start mai loop to shift out liveHeaders...once sync'd, will set `available` true.
|
|
147
149
|
this.promises.push(this.mainThreadShiftLiveHeaders());
|
|
148
150
|
// Wait for the main thread to finish initial sync.
|
|
149
|
-
while (!this.available) {
|
|
151
|
+
while (!this.available && !this.startupError) {
|
|
150
152
|
await (0, utilityHelpers_1.wait)(100);
|
|
151
153
|
}
|
|
154
|
+
if (this.startupError)
|
|
155
|
+
throw this.startupError;
|
|
152
156
|
});
|
|
153
157
|
}
|
|
154
158
|
async startPromises() {
|
|
@@ -376,142 +380,154 @@ class Chaintracks {
|
|
|
376
380
|
const cdnSyncRepeatMsecs = 24 * 60 * 60 * 1000; // 24 hours
|
|
377
381
|
const syncCheckRepeatMsecs = 30 * 60 * 1000; // 30 minutes
|
|
378
382
|
while (!this.stopMainThread) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
383
|
+
try {
|
|
384
|
+
// Review the need for bulk sync...
|
|
385
|
+
const now = Date.now();
|
|
386
|
+
lastSyncCheck = now;
|
|
387
|
+
const presentHeight = await this.getPresentHeight();
|
|
388
|
+
const before = await this.storage.getAvailableHeightRanges();
|
|
389
|
+
// Skip bulk sync if within less than half the recursion limit of present height
|
|
390
|
+
let skipBulkSync = !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2;
|
|
391
|
+
if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
|
|
392
|
+
// If we haven't re-synced in a long time, do it just to check for a CDN update.
|
|
393
|
+
skipBulkSync = false;
|
|
394
|
+
}
|
|
395
|
+
this.log(`Chaintracks Update Services: Bulk Header Sync Review
|
|
391
396
|
presentHeight=${presentHeight} addLiveRecursionLimit=${this.addLiveRecursionLimit}
|
|
392
397
|
Before synchronize: bulk ${before.bulk}, live ${before.live}
|
|
393
398
|
${skipBulkSync ? 'Skipping' : 'Starting'} syncBulkStorage.
|
|
394
399
|
`);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
needSyncCheck = true;
|
|
419
|
-
}
|
|
420
|
-
else if (ihr.noPrev) {
|
|
421
|
-
// Previous header is unknown, request it by hash from the network and try adding it first...
|
|
422
|
-
if (recursions-- <= 0) {
|
|
423
|
-
// Ignore this header...
|
|
424
|
-
this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
|
|
400
|
+
if (!skipBulkSync) {
|
|
401
|
+
// Bring bulk storage up-to-date and (re-)initialize liveHeaders
|
|
402
|
+
lastBulkSync = now;
|
|
403
|
+
if (this.available)
|
|
404
|
+
// Once available, initial write lock is released, take a new one to update bulk storage.
|
|
405
|
+
await this.syncBulkStorage(presentHeight, before);
|
|
406
|
+
else
|
|
407
|
+
// While still not available, the makeAvailable write lock is held.
|
|
408
|
+
await this.syncBulkStorageNoLock(presentHeight, before);
|
|
409
|
+
}
|
|
410
|
+
let count = 0;
|
|
411
|
+
let liveHeaderDupes = 0;
|
|
412
|
+
let needSyncCheck = false;
|
|
413
|
+
for (; !needSyncCheck && !this.stopMainThread;) {
|
|
414
|
+
let header = this.liveHeaders.shift();
|
|
415
|
+
if (header) {
|
|
416
|
+
// Process a "live" block header...
|
|
417
|
+
let recursions = this.addLiveRecursionLimit;
|
|
418
|
+
for (; !needSyncCheck && !this.stopMainThread;) {
|
|
419
|
+
//console.log(`Processing liveHeader: height: ${header.height} hash: ${header.hash} ${new Date().toISOString()}`)
|
|
420
|
+
const ihr = await this.addLiveHeader(header);
|
|
421
|
+
if (this.invalidInsertHeaderResult(ihr)) {
|
|
422
|
+
this.log(`Ignoring liveHeader ${header.height} ${header.hash} due to invalid insert result.`);
|
|
425
423
|
needSyncCheck = true;
|
|
426
424
|
}
|
|
427
|
-
else {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
this.log(`Ignoring liveHeader ${header.height} ${header.hash}
|
|
425
|
+
else if (ihr.noPrev) {
|
|
426
|
+
// Previous header is unknown, request it by hash from the network and try adding it first...
|
|
427
|
+
if (recursions-- <= 0) {
|
|
428
|
+
// Ignore this header...
|
|
429
|
+
this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
|
|
432
430
|
needSyncCheck = true;
|
|
433
431
|
}
|
|
434
432
|
else {
|
|
435
|
-
|
|
436
|
-
this.
|
|
437
|
-
|
|
433
|
+
const hash = header.previousHash;
|
|
434
|
+
const prevHeader = await this.getMissingBlockHeader(hash);
|
|
435
|
+
if (!prevHeader) {
|
|
436
|
+
this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${(0, utilityHelpers_noBuffer_1.asString)(hash)}`);
|
|
437
|
+
needSyncCheck = true;
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// Switch to trying to add prevHeader, unshifting current header to try it again after prevHeader exists.
|
|
441
|
+
this.liveHeaders.unshift(header);
|
|
442
|
+
header = prevHeader;
|
|
443
|
+
}
|
|
438
444
|
}
|
|
439
445
|
}
|
|
440
|
-
}
|
|
441
|
-
else {
|
|
442
|
-
if (this.subscriberCallbacksEnabled)
|
|
443
|
-
this.log(`addLiveHeader ${header.height}${ihr.added ? ' added' : ''}${ihr.dupe ? ' dupe' : ''}${ihr.isActiveTip ? ' isActiveTip' : ''}${ihr.reorgDepth ? ' reorg depth ' + ihr.reorgDepth : ''}${ihr.noPrev ? ' noPrev' : ''}${ihr.noActiveAncestor || ihr.noTip || ihr.badPrev ? ' error' : ''}`);
|
|
444
|
-
if (ihr.dupe) {
|
|
445
|
-
liveHeaderDupes++;
|
|
446
|
-
}
|
|
447
|
-
// Header wasn't invalid and previous header is known. If it was successfully added, count it as a win.
|
|
448
|
-
if (ihr.added) {
|
|
449
|
-
count++;
|
|
450
|
-
}
|
|
451
|
-
break;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
// There are no liveHeaders currently to process, check the out-of-band baseHeaders channel (`addHeader` method called by a client).
|
|
457
|
-
const bheader = this.baseHeaders.shift();
|
|
458
|
-
if (bheader) {
|
|
459
|
-
const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
|
|
460
|
-
if (!prev) {
|
|
461
|
-
// Ignoring attempt to add a baseHeader with unknown previous hash, no attempt made to find previous header(s).
|
|
462
|
-
this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
|
|
463
|
-
// Does not trigger a re-sync.
|
|
464
|
-
}
|
|
465
|
-
else {
|
|
466
|
-
const header = {
|
|
467
|
-
...bheader,
|
|
468
|
-
height: prev.height + 1,
|
|
469
|
-
hash: (0, blockHeaderUtilities_1.blockHash)(bheader)
|
|
470
|
-
};
|
|
471
|
-
const ihr = await this.addLiveHeader(header);
|
|
472
|
-
if (this.invalidInsertHeaderResult(ihr)) {
|
|
473
|
-
this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
|
|
474
|
-
}
|
|
475
446
|
else {
|
|
476
447
|
if (this.subscriberCallbacksEnabled)
|
|
477
|
-
this.log(`
|
|
478
|
-
|
|
448
|
+
this.log(`addLiveHeader ${header.height}${ihr.added ? ' added' : ''}${ihr.dupe ? ' dupe' : ''}${ihr.isActiveTip ? ' isActiveTip' : ''}${ihr.reorgDepth ? ' reorg depth ' + ihr.reorgDepth : ''}${ihr.noPrev ? ' noPrev' : ''}${ihr.noActiveAncestor || ihr.noTip || ihr.badPrev ? ' error' : ''}`);
|
|
449
|
+
if (ihr.dupe) {
|
|
450
|
+
liveHeaderDupes++;
|
|
451
|
+
}
|
|
452
|
+
// Header wasn't invalid and previous header is known. If it was successfully added, count it as a win.
|
|
479
453
|
if (ihr.added) {
|
|
480
454
|
count++;
|
|
481
455
|
}
|
|
456
|
+
break;
|
|
482
457
|
}
|
|
483
458
|
}
|
|
484
459
|
}
|
|
485
460
|
else {
|
|
486
|
-
// There are no liveHeaders
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
461
|
+
// There are no liveHeaders currently to process, check the out-of-band baseHeaders channel (`addHeader` method called by a client).
|
|
462
|
+
const bheader = this.baseHeaders.shift();
|
|
463
|
+
if (bheader) {
|
|
464
|
+
const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
|
|
465
|
+
if (!prev) {
|
|
466
|
+
// Ignoring attempt to add a baseHeader with unknown previous hash, no attempt made to find previous header(s).
|
|
467
|
+
this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
|
|
468
|
+
// Does not trigger a re-sync.
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
const header = {
|
|
472
|
+
...bheader,
|
|
473
|
+
height: prev.height + 1,
|
|
474
|
+
hash: (0, blockHeaderUtilities_1.blockHash)(bheader)
|
|
475
|
+
};
|
|
476
|
+
const ihr = await this.addLiveHeader(header);
|
|
477
|
+
if (this.invalidInsertHeaderResult(ihr)) {
|
|
478
|
+
this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
if (this.subscriberCallbacksEnabled)
|
|
482
|
+
this.log(`addBaseHeader ${header.height}${ihr.added ? ' added' : ''}${ihr.dupe ? ' dupe' : ''}${ihr.isActiveTip ? ' isActiveTip' : ''}${ihr.reorgDepth ? ' reorg depth ' + ihr.reorgDepth : ''}${ihr.noPrev ? ' noPrev' : ''}${ihr.noActiveAncestor || ihr.noTip || ihr.badPrev ? ' error' : ''}`);
|
|
483
|
+
// baseHeader was successfully added.
|
|
484
|
+
if (ihr.added) {
|
|
485
|
+
count++;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
491
488
|
}
|
|
492
|
-
|
|
493
|
-
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
// There are no liveHeaders and no baseHeaders to add,
|
|
492
|
+
if (count > 0) {
|
|
493
|
+
if (liveHeaderDupes > 0) {
|
|
494
|
+
this.log(`${liveHeaderDupes} duplicate headers ignored.`);
|
|
495
|
+
liveHeaderDupes = 0;
|
|
496
|
+
}
|
|
497
|
+
const updated = await this.storage.getAvailableHeightRanges();
|
|
498
|
+
this.log(`After adding ${count} live headers
|
|
494
499
|
After live: bulk ${updated.bulk}, live ${updated.live}
|
|
495
500
|
`);
|
|
496
|
-
|
|
497
|
-
}
|
|
498
|
-
if (!this.subscriberCallbacksEnabled) {
|
|
499
|
-
const live = await this.storage.findLiveHeightRange();
|
|
500
|
-
if (!live.isEmpty) {
|
|
501
|
-
this.subscriberCallbacksEnabled = true;
|
|
502
|
-
this.log(`listening at height of ${live.maxHeight}`);
|
|
501
|
+
count = 0;
|
|
503
502
|
}
|
|
503
|
+
if (!this.subscriberCallbacksEnabled) {
|
|
504
|
+
const live = await this.storage.findLiveHeightRange();
|
|
505
|
+
if (!live.isEmpty) {
|
|
506
|
+
this.subscriberCallbacksEnabled = true;
|
|
507
|
+
this.log(`listening at height of ${live.maxHeight}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (!this.available) {
|
|
511
|
+
this.available = true;
|
|
512
|
+
}
|
|
513
|
+
needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
|
|
514
|
+
// If we aren't going to review sync, wait before checking input queues again
|
|
515
|
+
if (!needSyncCheck)
|
|
516
|
+
await (0, utilityHelpers_1.wait)(1000);
|
|
504
517
|
}
|
|
505
|
-
if (!this.available) {
|
|
506
|
-
this.available = true;
|
|
507
|
-
}
|
|
508
|
-
needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
|
|
509
|
-
// If we aren't going to review sync, wait before checking input queues again
|
|
510
|
-
if (!needSyncCheck)
|
|
511
|
-
await (0, utilityHelpers_1.wait)(1000);
|
|
512
518
|
}
|
|
513
519
|
}
|
|
514
520
|
}
|
|
521
|
+
catch (eu) {
|
|
522
|
+
const e = WalletError_1.WalletError.fromUnknown(eu);
|
|
523
|
+
if (!this.available) {
|
|
524
|
+
this.startupError = e;
|
|
525
|
+
this.stopMainThread = true;
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
this.log(`Error occurred during chaintracks main thread processing: ${e.stack || e.message}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
515
531
|
}
|
|
516
532
|
}
|
|
517
533
|
}
|