@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.
Files changed (25) hide show
  1. package/docs/client.md +123 -93
  2. package/docs/services.md +123 -93
  3. package/docs/wallet.md +123 -93
  4. package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts +1 -0
  5. package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts.map +1 -1
  6. package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.js +125 -109
  7. package/mobile/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
  8. package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts +16 -4
  9. package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
  10. package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +65 -45
  11. package/mobile/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
  12. package/mobile/package-lock.json +2 -2
  13. package/mobile/package.json +1 -1
  14. package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts +1 -0
  15. package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts.map +1 -1
  16. package/out/src/services/chaintracker/chaintracks/Chaintracks.js +125 -109
  17. package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
  18. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts +16 -4
  19. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
  20. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +65 -45
  21. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
  22. package/out/tsconfig.all.tsbuildinfo +1 -1
  23. package/package.json +1 -1
  24. package/src/services/chaintracker/chaintracks/Chaintracks.ts +124 -109
  25. package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +75 -50
package/docs/client.md CHANGED
@@ -8516,10 +8516,15 @@ export class BulkFileDataManager {
8516
8516
  readonly maxRetained?: number;
8517
8517
  readonly fromKnownSourceUrl?: string;
8518
8518
  constructor(options: BulkFileDataManagerOptions | Chain)
8519
+ async deleteBulkFiles(): Promise<void>
8520
+ async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
8521
+ heightRangesFromBulkFiles(files: BulkHeaderFileInfo[]): {
8522
+ all: HeightRange;
8523
+ cdn: HeightRange;
8524
+ incremental: HeightRange;
8525
+ }
8519
8526
  async createReader(range?: HeightRange, maxBufferSize?: number): Promise<BulkFileDataReader>
8520
8527
  async updateFromUrl(cdnUrl: string): Promise<void>
8521
- async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
8522
- async deleteBulkFiles(): Promise<void>
8523
8528
  async merge(files: BulkHeaderFileInfo[]): Promise<BulkFileDataManagerMergeResult>
8524
8529
  toLogString(what?: BulkFileDataManagerMergeResult | BulkFileData[] | BulkHeaderFileInfo[]): string
8525
8530
  async mergeIncrementalBlockHeaders(newBulkHeaders: BlockHeader[], incrementalChainWork?: string): Promise<void>
@@ -8536,6 +8541,19 @@ export class BulkFileDataManager {
8536
8541
 
8537
8542
  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)
8538
8543
 
8544
+ ###### Method setStorage
8545
+
8546
+ If `bfds` are going to be backed by persistent storage,
8547
+ must be called before making storage available.
8548
+
8549
+ Synchronizes bfds and storage files, after which this manager maintains sync.
8550
+ There should be no changes to bulk files by direct access to storage bulk file methods.
8551
+
8552
+ ```ts
8553
+ async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
8554
+ ```
8555
+ See also: [ChaintracksStorageBulkFileApi](./services.md#interface-chaintracksstoragebulkfileapi)
8556
+
8539
8557
  Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
8540
8558
 
8541
8559
  ---
@@ -9404,130 +9422,142 @@ export class Chaintracks implements ChaintracksManagementApi {
9404
9422
  const cdnSyncRepeatMsecs = 24 * 60 * 60 * 1000;
9405
9423
  const syncCheckRepeatMsecs = 30 * 60 * 1000;
9406
9424
  while (!this.stopMainThread) {
9407
- const now = Date.now();
9408
- lastSyncCheck = now;
9409
- const presentHeight = await this.getPresentHeight();
9410
- const before = await this.storage.getAvailableHeightRanges();
9411
- let skipBulkSync = !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2;
9412
- if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
9413
- skipBulkSync = false;
9414
- }
9415
- this.log(`Chaintracks Update Services: Bulk Header Sync Review
9425
+ try {
9426
+ const now = Date.now();
9427
+ lastSyncCheck = now;
9428
+ const presentHeight = await this.getPresentHeight();
9429
+ const before = await this.storage.getAvailableHeightRanges();
9430
+ let skipBulkSync = !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2;
9431
+ if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
9432
+ skipBulkSync = false;
9433
+ }
9434
+ this.log(`Chaintracks Update Services: Bulk Header Sync Review
9416
9435
  presentHeight=${presentHeight} addLiveRecursionLimit=${this.addLiveRecursionLimit}
9417
9436
  Before synchronize: bulk ${before.bulk}, live ${before.live}
9418
9437
  ${skipBulkSync ? "Skipping" : "Starting"} syncBulkStorage.
9419
9438
  `);
9420
- if (!skipBulkSync) {
9421
- lastBulkSync = now;
9422
- if (this.available)
9423
- await this.syncBulkStorage(presentHeight, before);
9424
- else
9425
- await this.syncBulkStorageNoLock(presentHeight, before);
9426
- }
9427
- let count = 0;
9428
- let liveHeaderDupes = 0;
9429
- let needSyncCheck = false;
9430
- for (; !needSyncCheck && !this.stopMainThread;) {
9431
- let header = this.liveHeaders.shift();
9432
- if (header) {
9433
- let recursions = this.addLiveRecursionLimit;
9434
- for (; !needSyncCheck && !this.stopMainThread;) {
9435
- const ihr = await this.addLiveHeader(header);
9436
- if (this.invalidInsertHeaderResult(ihr)) {
9437
- this.log(`Ignoring liveHeader ${header.height} ${header.hash} due to invalid insert result.`);
9438
- needSyncCheck = true;
9439
- }
9440
- else if (ihr.noPrev) {
9441
- if (recursions-- <= 0) {
9442
- this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
9439
+ if (!skipBulkSync) {
9440
+ lastBulkSync = now;
9441
+ if (this.available)
9442
+ await this.syncBulkStorage(presentHeight, before);
9443
+ else
9444
+ await this.syncBulkStorageNoLock(presentHeight, before);
9445
+ }
9446
+ let count = 0;
9447
+ let liveHeaderDupes = 0;
9448
+ let needSyncCheck = false;
9449
+ for (; !needSyncCheck && !this.stopMainThread;) {
9450
+ let header = this.liveHeaders.shift();
9451
+ if (header) {
9452
+ let recursions = this.addLiveRecursionLimit;
9453
+ for (; !needSyncCheck && !this.stopMainThread;) {
9454
+ const ihr = await this.addLiveHeader(header);
9455
+ if (this.invalidInsertHeaderResult(ihr)) {
9456
+ this.log(`Ignoring liveHeader ${header.height} ${header.hash} due to invalid insert result.`);
9443
9457
  needSyncCheck = true;
9444
9458
  }
9445
- else {
9446
- const hash = header.previousHash;
9447
- const prevHeader = await this.getMissingBlockHeader(hash);
9448
- if (!prevHeader) {
9449
- this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${asString(hash)}`);
9459
+ else if (ihr.noPrev) {
9460
+ if (recursions-- <= 0) {
9461
+ this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
9450
9462
  needSyncCheck = true;
9451
9463
  }
9452
9464
  else {
9453
- this.liveHeaders.unshift(header);
9454
- header = prevHeader;
9465
+ const hash = header.previousHash;
9466
+ const prevHeader = await this.getMissingBlockHeader(hash);
9467
+ if (!prevHeader) {
9468
+ this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${asString(hash)}`);
9469
+ needSyncCheck = true;
9470
+ }
9471
+ else {
9472
+ this.liveHeaders.unshift(header);
9473
+ header = prevHeader;
9474
+ }
9455
9475
  }
9456
9476
  }
9457
- }
9458
- else {
9459
- if (this.subscriberCallbacksEnabled)
9460
- 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" : ""}`);
9461
- if (ihr.dupe) {
9462
- liveHeaderDupes++;
9463
- }
9464
- if (ihr.added) {
9465
- count++;
9466
- }
9467
- break;
9468
- }
9469
- }
9470
- }
9471
- else {
9472
- const bheader = this.baseHeaders.shift();
9473
- if (bheader) {
9474
- const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
9475
- if (!prev) {
9476
- this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
9477
- }
9478
- else {
9479
- const header: BlockHeader = {
9480
- ...bheader,
9481
- height: prev.height + 1,
9482
- hash: blockHash(bheader)
9483
- };
9484
- const ihr = await this.addLiveHeader(header);
9485
- if (this.invalidInsertHeaderResult(ihr)) {
9486
- this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
9487
- }
9488
9477
  else {
9489
9478
  if (this.subscriberCallbacksEnabled)
9490
- 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" : ""}`);
9479
+ 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" : ""}`);
9480
+ if (ihr.dupe) {
9481
+ liveHeaderDupes++;
9482
+ }
9491
9483
  if (ihr.added) {
9492
9484
  count++;
9493
9485
  }
9486
+ break;
9494
9487
  }
9495
9488
  }
9496
9489
  }
9497
9490
  else {
9498
- if (count > 0) {
9499
- if (liveHeaderDupes > 0) {
9500
- this.log(`${liveHeaderDupes} duplicate headers ignored.`);
9501
- liveHeaderDupes = 0;
9491
+ const bheader = this.baseHeaders.shift();
9492
+ if (bheader) {
9493
+ const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
9494
+ if (!prev) {
9495
+ this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
9496
+ }
9497
+ else {
9498
+ const header: BlockHeader = {
9499
+ ...bheader,
9500
+ height: prev.height + 1,
9501
+ hash: blockHash(bheader)
9502
+ };
9503
+ const ihr = await this.addLiveHeader(header);
9504
+ if (this.invalidInsertHeaderResult(ihr)) {
9505
+ this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
9506
+ }
9507
+ else {
9508
+ if (this.subscriberCallbacksEnabled)
9509
+ 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" : ""}`);
9510
+ if (ihr.added) {
9511
+ count++;
9512
+ }
9513
+ }
9502
9514
  }
9503
- const updated = await this.storage.getAvailableHeightRanges();
9504
- this.log(`After adding ${count} live headers
9515
+ }
9516
+ else {
9517
+ if (count > 0) {
9518
+ if (liveHeaderDupes > 0) {
9519
+ this.log(`${liveHeaderDupes} duplicate headers ignored.`);
9520
+ liveHeaderDupes = 0;
9521
+ }
9522
+ const updated = await this.storage.getAvailableHeightRanges();
9523
+ this.log(`After adding ${count} live headers
9505
9524
  After live: bulk ${updated.bulk}, live ${updated.live}
9506
9525
  `);
9507
- count = 0;
9508
- }
9509
- if (!this.subscriberCallbacksEnabled) {
9510
- const live = await this.storage.findLiveHeightRange();
9511
- if (!live.isEmpty) {
9512
- this.subscriberCallbacksEnabled = true;
9513
- this.log(`listening at height of ${live.maxHeight}`);
9526
+ count = 0;
9514
9527
  }
9528
+ if (!this.subscriberCallbacksEnabled) {
9529
+ const live = await this.storage.findLiveHeightRange();
9530
+ if (!live.isEmpty) {
9531
+ this.subscriberCallbacksEnabled = true;
9532
+ this.log(`listening at height of ${live.maxHeight}`);
9533
+ }
9534
+ }
9535
+ if (!this.available) {
9536
+ this.available = true;
9537
+ }
9538
+ needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
9539
+ if (!needSyncCheck)
9540
+ await wait(1000);
9515
9541
  }
9516
- if (!this.available) {
9517
- this.available = true;
9518
- }
9519
- needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
9520
- if (!needSyncCheck)
9521
- await wait(1000);
9522
9542
  }
9523
9543
  }
9524
9544
  }
9545
+ catch (eu: unknown) {
9546
+ const e = WalletError.fromUnknown(eu);
9547
+ if (!this.available) {
9548
+ this.startupError = e;
9549
+ this.stopMainThread = true;
9550
+ }
9551
+ else {
9552
+ this.log(`Error occurred during chaintracks main thread processing: ${e.stack || e.message}`);
9553
+ }
9554
+ }
9525
9555
  }
9526
9556
  }
9527
9557
  }
9528
9558
  ```
9529
9559
 
9530
- 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)
9560
+ 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)
9531
9561
 
9532
9562
  ###### Method addHeader
9533
9563
 
package/docs/services.md CHANGED
@@ -2835,10 +2835,15 @@ export class BulkFileDataManager {
2835
2835
  readonly maxRetained?: number;
2836
2836
  readonly fromKnownSourceUrl?: string;
2837
2837
  constructor(options: BulkFileDataManagerOptions | Chain)
2838
+ async deleteBulkFiles(): Promise<void>
2839
+ async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
2840
+ heightRangesFromBulkFiles(files: BulkHeaderFileInfo[]): {
2841
+ all: HeightRange;
2842
+ cdn: HeightRange;
2843
+ incremental: HeightRange;
2844
+ }
2838
2845
  async createReader(range?: HeightRange, maxBufferSize?: number): Promise<BulkFileDataReader>
2839
2846
  async updateFromUrl(cdnUrl: string): Promise<void>
2840
- async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
2841
- async deleteBulkFiles(): Promise<void>
2842
2847
  async merge(files: BulkHeaderFileInfo[]): Promise<BulkFileDataManagerMergeResult>
2843
2848
  toLogString(what?: BulkFileDataManagerMergeResult | BulkFileData[] | BulkHeaderFileInfo[]): string
2844
2849
  async mergeIncrementalBlockHeaders(newBulkHeaders: BlockHeader[], incrementalChainWork?: string): Promise<void>
@@ -2855,6 +2860,19 @@ export class BulkFileDataManager {
2855
2860
 
2856
2861
  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)
2857
2862
 
2863
+ ###### Method setStorage
2864
+
2865
+ If `bfds` are going to be backed by persistent storage,
2866
+ must be called before making storage available.
2867
+
2868
+ Synchronizes bfds and storage files, after which this manager maintains sync.
2869
+ There should be no changes to bulk files by direct access to storage bulk file methods.
2870
+
2871
+ ```ts
2872
+ async setStorage(storage: ChaintracksStorageBulkFileApi, log: (...args: any[]) => void): Promise<void>
2873
+ ```
2874
+ See also: [ChaintracksStorageBulkFileApi](./services.md#interface-chaintracksstoragebulkfileapi)
2875
+
2858
2876
  Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
2859
2877
 
2860
2878
  ---
@@ -3481,130 +3499,142 @@ export class Chaintracks implements ChaintracksManagementApi {
3481
3499
  const cdnSyncRepeatMsecs = 24 * 60 * 60 * 1000;
3482
3500
  const syncCheckRepeatMsecs = 30 * 60 * 1000;
3483
3501
  while (!this.stopMainThread) {
3484
- const now = Date.now();
3485
- lastSyncCheck = now;
3486
- const presentHeight = await this.getPresentHeight();
3487
- const before = await this.storage.getAvailableHeightRanges();
3488
- let skipBulkSync = !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2;
3489
- if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
3490
- skipBulkSync = false;
3491
- }
3492
- this.log(`Chaintracks Update Services: Bulk Header Sync Review
3502
+ try {
3503
+ const now = Date.now();
3504
+ lastSyncCheck = now;
3505
+ const presentHeight = await this.getPresentHeight();
3506
+ const before = await this.storage.getAvailableHeightRanges();
3507
+ let skipBulkSync = !before.live.isEmpty && before.live.maxHeight >= presentHeight - this.addLiveRecursionLimit / 2;
3508
+ if (skipBulkSync && now - lastSyncCheck > cdnSyncRepeatMsecs) {
3509
+ skipBulkSync = false;
3510
+ }
3511
+ this.log(`Chaintracks Update Services: Bulk Header Sync Review
3493
3512
  presentHeight=${presentHeight} addLiveRecursionLimit=${this.addLiveRecursionLimit}
3494
3513
  Before synchronize: bulk ${before.bulk}, live ${before.live}
3495
3514
  ${skipBulkSync ? "Skipping" : "Starting"} syncBulkStorage.
3496
3515
  `);
3497
- if (!skipBulkSync) {
3498
- lastBulkSync = now;
3499
- if (this.available)
3500
- await this.syncBulkStorage(presentHeight, before);
3501
- else
3502
- await this.syncBulkStorageNoLock(presentHeight, before);
3503
- }
3504
- let count = 0;
3505
- let liveHeaderDupes = 0;
3506
- let needSyncCheck = false;
3507
- for (; !needSyncCheck && !this.stopMainThread;) {
3508
- let header = this.liveHeaders.shift();
3509
- if (header) {
3510
- let recursions = this.addLiveRecursionLimit;
3511
- for (; !needSyncCheck && !this.stopMainThread;) {
3512
- const ihr = await this.addLiveHeader(header);
3513
- if (this.invalidInsertHeaderResult(ihr)) {
3514
- this.log(`Ignoring liveHeader ${header.height} ${header.hash} due to invalid insert result.`);
3515
- needSyncCheck = true;
3516
- }
3517
- else if (ihr.noPrev) {
3518
- if (recursions-- <= 0) {
3519
- this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
3516
+ if (!skipBulkSync) {
3517
+ lastBulkSync = now;
3518
+ if (this.available)
3519
+ await this.syncBulkStorage(presentHeight, before);
3520
+ else
3521
+ await this.syncBulkStorageNoLock(presentHeight, before);
3522
+ }
3523
+ let count = 0;
3524
+ let liveHeaderDupes = 0;
3525
+ let needSyncCheck = false;
3526
+ for (; !needSyncCheck && !this.stopMainThread;) {
3527
+ let header = this.liveHeaders.shift();
3528
+ if (header) {
3529
+ let recursions = this.addLiveRecursionLimit;
3530
+ for (; !needSyncCheck && !this.stopMainThread;) {
3531
+ const ihr = await this.addLiveHeader(header);
3532
+ if (this.invalidInsertHeaderResult(ihr)) {
3533
+ this.log(`Ignoring liveHeader ${header.height} ${header.hash} due to invalid insert result.`);
3520
3534
  needSyncCheck = true;
3521
3535
  }
3522
- else {
3523
- const hash = header.previousHash;
3524
- const prevHeader = await this.getMissingBlockHeader(hash);
3525
- if (!prevHeader) {
3526
- this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${asString(hash)}`);
3536
+ else if (ihr.noPrev) {
3537
+ if (recursions-- <= 0) {
3538
+ this.log(`Ignoring liveHeader ${header.height} ${header.hash} addLiveRecursionLimit=${this.addLiveRecursionLimit} exceeded.`);
3527
3539
  needSyncCheck = true;
3528
3540
  }
3529
3541
  else {
3530
- this.liveHeaders.unshift(header);
3531
- header = prevHeader;
3542
+ const hash = header.previousHash;
3543
+ const prevHeader = await this.getMissingBlockHeader(hash);
3544
+ if (!prevHeader) {
3545
+ this.log(`Ignoring liveHeader ${header.height} ${header.hash} failed to find previous header by hash ${asString(hash)}`);
3546
+ needSyncCheck = true;
3547
+ }
3548
+ else {
3549
+ this.liveHeaders.unshift(header);
3550
+ header = prevHeader;
3551
+ }
3532
3552
  }
3533
3553
  }
3534
- }
3535
- else {
3536
- if (this.subscriberCallbacksEnabled)
3537
- 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" : ""}`);
3538
- if (ihr.dupe) {
3539
- liveHeaderDupes++;
3540
- }
3541
- if (ihr.added) {
3542
- count++;
3543
- }
3544
- break;
3545
- }
3546
- }
3547
- }
3548
- else {
3549
- const bheader = this.baseHeaders.shift();
3550
- if (bheader) {
3551
- const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
3552
- if (!prev) {
3553
- this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
3554
- }
3555
- else {
3556
- const header: BlockHeader = {
3557
- ...bheader,
3558
- height: prev.height + 1,
3559
- hash: blockHash(bheader)
3560
- };
3561
- const ihr = await this.addLiveHeader(header);
3562
- if (this.invalidInsertHeaderResult(ihr)) {
3563
- this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
3564
- }
3565
3554
  else {
3566
3555
  if (this.subscriberCallbacksEnabled)
3567
- 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" : ""}`);
3556
+ 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" : ""}`);
3557
+ if (ihr.dupe) {
3558
+ liveHeaderDupes++;
3559
+ }
3568
3560
  if (ihr.added) {
3569
3561
  count++;
3570
3562
  }
3563
+ break;
3571
3564
  }
3572
3565
  }
3573
3566
  }
3574
3567
  else {
3575
- if (count > 0) {
3576
- if (liveHeaderDupes > 0) {
3577
- this.log(`${liveHeaderDupes} duplicate headers ignored.`);
3578
- liveHeaderDupes = 0;
3568
+ const bheader = this.baseHeaders.shift();
3569
+ if (bheader) {
3570
+ const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
3571
+ if (!prev) {
3572
+ this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
3573
+ }
3574
+ else {
3575
+ const header: BlockHeader = {
3576
+ ...bheader,
3577
+ height: prev.height + 1,
3578
+ hash: blockHash(bheader)
3579
+ };
3580
+ const ihr = await this.addLiveHeader(header);
3581
+ if (this.invalidInsertHeaderResult(ihr)) {
3582
+ this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
3583
+ }
3584
+ else {
3585
+ if (this.subscriberCallbacksEnabled)
3586
+ 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" : ""}`);
3587
+ if (ihr.added) {
3588
+ count++;
3589
+ }
3590
+ }
3579
3591
  }
3580
- const updated = await this.storage.getAvailableHeightRanges();
3581
- this.log(`After adding ${count} live headers
3592
+ }
3593
+ else {
3594
+ if (count > 0) {
3595
+ if (liveHeaderDupes > 0) {
3596
+ this.log(`${liveHeaderDupes} duplicate headers ignored.`);
3597
+ liveHeaderDupes = 0;
3598
+ }
3599
+ const updated = await this.storage.getAvailableHeightRanges();
3600
+ this.log(`After adding ${count} live headers
3582
3601
  After live: bulk ${updated.bulk}, live ${updated.live}
3583
3602
  `);
3584
- count = 0;
3585
- }
3586
- if (!this.subscriberCallbacksEnabled) {
3587
- const live = await this.storage.findLiveHeightRange();
3588
- if (!live.isEmpty) {
3589
- this.subscriberCallbacksEnabled = true;
3590
- this.log(`listening at height of ${live.maxHeight}`);
3603
+ count = 0;
3591
3604
  }
3605
+ if (!this.subscriberCallbacksEnabled) {
3606
+ const live = await this.storage.findLiveHeightRange();
3607
+ if (!live.isEmpty) {
3608
+ this.subscriberCallbacksEnabled = true;
3609
+ this.log(`listening at height of ${live.maxHeight}`);
3610
+ }
3611
+ }
3612
+ if (!this.available) {
3613
+ this.available = true;
3614
+ }
3615
+ needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
3616
+ if (!needSyncCheck)
3617
+ await wait(1000);
3592
3618
  }
3593
- if (!this.available) {
3594
- this.available = true;
3595
- }
3596
- needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
3597
- if (!needSyncCheck)
3598
- await wait(1000);
3599
3619
  }
3600
3620
  }
3601
3621
  }
3622
+ catch (eu: unknown) {
3623
+ const e = WalletError.fromUnknown(eu);
3624
+ if (!this.available) {
3625
+ this.startupError = e;
3626
+ this.stopMainThread = true;
3627
+ }
3628
+ else {
3629
+ this.log(`Error occurred during chaintracks main thread processing: ${e.stack || e.message}`);
3630
+ }
3631
+ }
3602
3632
  }
3603
3633
  }
3604
3634
  }
3605
3635
  ```
3606
3636
 
3607
- 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)
3637
+ 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)
3608
3638
 
3609
3639
  ###### Method addHeader
3610
3640