@bsv/wallet-toolbox 1.6.15 → 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 +103 -91
- package/docs/services.md +103 -91
- package/docs/wallet.md +103 -91
- 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/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/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/services/chaintracker/chaintracks/Chaintracks.ts +124 -109
package/docs/wallet.md
CHANGED
|
@@ -9421,130 +9421,142 @@ export class Chaintracks implements ChaintracksManagementApi {
|
|
|
9421
9421
|
const cdnSyncRepeatMsecs = 24 * 60 * 60 * 1000;
|
|
9422
9422
|
const syncCheckRepeatMsecs = 30 * 60 * 1000;
|
|
9423
9423
|
while (!this.stopMainThread) {
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
skipBulkSync
|
|
9431
|
-
|
|
9432
|
-
|
|
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
|
|
9433
9434
|
presentHeight=${presentHeight} addLiveRecursionLimit=${this.addLiveRecursionLimit}
|
|
9434
9435
|
Before synchronize: bulk ${before.bulk}, live ${before.live}
|
|
9435
9436
|
${skipBulkSync ? "Skipping" : "Starting"} syncBulkStorage.
|
|
9436
9437
|
`);
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
needSyncCheck = true;
|
|
9456
|
-
}
|
|
9457
|
-
else if (ihr.noPrev) {
|
|
9458
|
-
if (recursions-- <= 0) {
|
|
9459
|
-
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.`);
|
|
9460
9456
|
needSyncCheck = true;
|
|
9461
9457
|
}
|
|
9462
|
-
else {
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
if (!prevHeader) {
|
|
9466
|
-
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.`);
|
|
9467
9461
|
needSyncCheck = true;
|
|
9468
9462
|
}
|
|
9469
9463
|
else {
|
|
9470
|
-
|
|
9471
|
-
|
|
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
|
+
}
|
|
9472
9474
|
}
|
|
9473
9475
|
}
|
|
9474
|
-
}
|
|
9475
|
-
else {
|
|
9476
|
-
if (this.subscriberCallbacksEnabled)
|
|
9477
|
-
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" : ""}`);
|
|
9478
|
-
if (ihr.dupe) {
|
|
9479
|
-
liveHeaderDupes++;
|
|
9480
|
-
}
|
|
9481
|
-
if (ihr.added) {
|
|
9482
|
-
count++;
|
|
9483
|
-
}
|
|
9484
|
-
break;
|
|
9485
|
-
}
|
|
9486
|
-
}
|
|
9487
|
-
}
|
|
9488
|
-
else {
|
|
9489
|
-
const bheader = this.baseHeaders.shift();
|
|
9490
|
-
if (bheader) {
|
|
9491
|
-
const prev = await this.storage.findLiveHeaderForBlockHash(bheader.previousHash);
|
|
9492
|
-
if (!prev) {
|
|
9493
|
-
this.log(`Ignoring header with unknown previousHash ${bheader.previousHash} in live storage.`);
|
|
9494
|
-
}
|
|
9495
|
-
else {
|
|
9496
|
-
const header: BlockHeader = {
|
|
9497
|
-
...bheader,
|
|
9498
|
-
height: prev.height + 1,
|
|
9499
|
-
hash: blockHash(bheader)
|
|
9500
|
-
};
|
|
9501
|
-
const ihr = await this.addLiveHeader(header);
|
|
9502
|
-
if (this.invalidInsertHeaderResult(ihr)) {
|
|
9503
|
-
this.log(`Ignoring invalid baseHeader ${header.height} ${header.hash}.`);
|
|
9504
|
-
}
|
|
9505
9476
|
else {
|
|
9506
9477
|
if (this.subscriberCallbacksEnabled)
|
|
9507
|
-
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
|
+
}
|
|
9508
9482
|
if (ihr.added) {
|
|
9509
9483
|
count++;
|
|
9510
9484
|
}
|
|
9485
|
+
break;
|
|
9511
9486
|
}
|
|
9512
9487
|
}
|
|
9513
9488
|
}
|
|
9514
9489
|
else {
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
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
|
+
}
|
|
9519
9513
|
}
|
|
9520
|
-
|
|
9521
|
-
|
|
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
|
|
9522
9523
|
After live: bulk ${updated.bulk}, live ${updated.live}
|
|
9523
9524
|
`);
|
|
9524
|
-
|
|
9525
|
-
}
|
|
9526
|
-
if (!this.subscriberCallbacksEnabled) {
|
|
9527
|
-
const live = await this.storage.findLiveHeightRange();
|
|
9528
|
-
if (!live.isEmpty) {
|
|
9529
|
-
this.subscriberCallbacksEnabled = true;
|
|
9530
|
-
this.log(`listening at height of ${live.maxHeight}`);
|
|
9525
|
+
count = 0;
|
|
9531
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);
|
|
9532
9540
|
}
|
|
9533
|
-
if (!this.available) {
|
|
9534
|
-
this.available = true;
|
|
9535
|
-
}
|
|
9536
|
-
needSyncCheck = Date.now() - lastSyncCheck > syncCheckRepeatMsecs;
|
|
9537
|
-
if (!needSyncCheck)
|
|
9538
|
-
await wait(1000);
|
|
9539
9541
|
}
|
|
9540
9542
|
}
|
|
9541
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
|
+
}
|
|
9542
9554
|
}
|
|
9543
9555
|
}
|
|
9544
9556
|
}
|
|
9545
9557
|
```
|
|
9546
9558
|
|
|
9547
|
-
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)
|
|
9548
9560
|
|
|
9549
9561
|
###### Method addHeader
|
|
9550
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":"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"}
|
|
@@ -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
|
}
|