@leofcoin/chain 1.4.75 → 1.4.76
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/exports/browser/chain.js +100 -28
- package/exports/chain.js +100 -28
- package/exports/typings/jobs/jobber.d.ts +7 -0
- package/package.json +1 -1
- package/exports/typings/jobs/sync.d.ts +0 -3
package/exports/browser/chain.js
CHANGED
|
@@ -1818,7 +1818,33 @@ class Machine {
|
|
|
1818
1818
|
}
|
|
1819
1819
|
}
|
|
1820
1820
|
|
|
1821
|
-
|
|
1821
|
+
class Jobber {
|
|
1822
|
+
timeout;
|
|
1823
|
+
busy = false;
|
|
1824
|
+
stop;
|
|
1825
|
+
constructor(timeout) {
|
|
1826
|
+
this.timeout = timeout;
|
|
1827
|
+
}
|
|
1828
|
+
add(fn) {
|
|
1829
|
+
this.busy = true;
|
|
1830
|
+
return new Promise(async (resolve, reject) => {
|
|
1831
|
+
const timeout = setTimeout(() => {
|
|
1832
|
+
reject('timeout');
|
|
1833
|
+
}, this.timeout);
|
|
1834
|
+
this.stop = () => {
|
|
1835
|
+
clearTimeout(timeout);
|
|
1836
|
+
this.busy = false;
|
|
1837
|
+
resolve('stopped');
|
|
1838
|
+
};
|
|
1839
|
+
const result = await fn();
|
|
1840
|
+
clearTimeout(timeout);
|
|
1841
|
+
this.busy = false;
|
|
1842
|
+
resolve(result);
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
new PQueue({ concurrency: 1, throwOnTimeout: true });
|
|
1822
1848
|
class State extends Contract {
|
|
1823
1849
|
#resolveErrored;
|
|
1824
1850
|
#lastResolvedTime;
|
|
@@ -1832,9 +1858,16 @@ class State extends Contract {
|
|
|
1832
1858
|
#chainSyncing = false;
|
|
1833
1859
|
#lastBlock = { index: 0, hash: '0x0', previousHash: '0x0' };
|
|
1834
1860
|
#blocks = [];
|
|
1835
|
-
|
|
1861
|
+
knownBlocks = [];
|
|
1836
1862
|
#totalSize = 0;
|
|
1837
1863
|
#machine;
|
|
1864
|
+
#loaded = false;
|
|
1865
|
+
get loaded() {
|
|
1866
|
+
return this.#loaded;
|
|
1867
|
+
}
|
|
1868
|
+
get resolving() {
|
|
1869
|
+
return this.#resolving;
|
|
1870
|
+
}
|
|
1838
1871
|
/**
|
|
1839
1872
|
* amount the native token has been iteracted with
|
|
1840
1873
|
*/
|
|
@@ -1889,6 +1922,7 @@ class State extends Contract {
|
|
|
1889
1922
|
super();
|
|
1890
1923
|
}
|
|
1891
1924
|
async init() {
|
|
1925
|
+
this.jobber = new Jobber(30_000);
|
|
1892
1926
|
if (super.init)
|
|
1893
1927
|
await super.init();
|
|
1894
1928
|
await globalThis.peernet.addRequestHandler('lastBlock', this.#lastBlockHandler.bind(this));
|
|
@@ -1961,18 +1995,27 @@ class State extends Contract {
|
|
|
1961
1995
|
return;
|
|
1962
1996
|
}
|
|
1963
1997
|
}
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1998
|
+
try {
|
|
1999
|
+
const block = await this.getAndPutBlock(hash);
|
|
2000
|
+
index = block.decoded.index;
|
|
2001
|
+
const size = block.encoded.length > 0 ? block.encoded.length : block.encoded.byteLength;
|
|
2002
|
+
this.#totalSize += size;
|
|
2003
|
+
this.#blocks[index] = { hash, ...block.decoded };
|
|
2004
|
+
this.#blockHashMap.set(hash, index);
|
|
2005
|
+
globalThis.debug(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
|
|
2006
|
+
this.#lastResolved = this.#blocks[index];
|
|
2007
|
+
this.#lastResolvedTime = Date.now();
|
|
2008
|
+
}
|
|
2009
|
+
catch (error) {
|
|
2010
|
+
this.#resolving = false;
|
|
2011
|
+
this.#chainSyncing = false;
|
|
2012
|
+
throw new Error('resolve error');
|
|
2013
|
+
}
|
|
1973
2014
|
return;
|
|
1974
2015
|
}
|
|
1975
2016
|
async resolveBlock(hash) {
|
|
2017
|
+
if (this.#resolveErrorCount === 3)
|
|
2018
|
+
this.#resolveErrorCount = 0;
|
|
1976
2019
|
if (!hash)
|
|
1977
2020
|
throw new Error(`expected hash, got: ${hash}`);
|
|
1978
2021
|
if (hash === '0x0')
|
|
@@ -1980,19 +2023,36 @@ class State extends Contract {
|
|
|
1980
2023
|
if (this.#resolving)
|
|
1981
2024
|
return 'already resolving';
|
|
1982
2025
|
this.#resolving = true;
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
2026
|
+
try {
|
|
2027
|
+
await this.jobber.add(() => this.#resolveBlock(hash));
|
|
2028
|
+
this.#resolving = false;
|
|
2029
|
+
if (!this.#blockHashMap.has(this.#lastResolved.previousHash) && this.#lastResolved.previousHash !== '0x0')
|
|
2030
|
+
return this.resolveBlock(this.#lastResolved.previousHash);
|
|
2031
|
+
}
|
|
2032
|
+
catch (error) {
|
|
2033
|
+
this.#resolveErrorCount += 1;
|
|
2034
|
+
if (this.#resolveErrorCount < 3)
|
|
2035
|
+
return this.resolveBlock(hash);
|
|
2036
|
+
else
|
|
2037
|
+
throw new Error('resolve errored');
|
|
2038
|
+
}
|
|
1988
2039
|
}
|
|
1989
2040
|
async resolveBlocks() {
|
|
2041
|
+
try {
|
|
2042
|
+
if (this.jobber.busy && this.jobber.stop) {
|
|
2043
|
+
await this.jobber.stop();
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
catch (error) {
|
|
2047
|
+
console.error(error);
|
|
2048
|
+
}
|
|
1990
2049
|
try {
|
|
1991
2050
|
const localBlock = await globalThis.chainStore.get('lastBlock');
|
|
1992
2051
|
const hash = new TextDecoder().decode(localBlock);
|
|
1993
|
-
if (hash && hash !== '0x0')
|
|
2052
|
+
if (hash && hash !== '0x0') {
|
|
1994
2053
|
await this.resolveBlock(hash);
|
|
1995
|
-
|
|
2054
|
+
this.#lastBlock = this.#blocks[this.#blocks.length - 1];
|
|
2055
|
+
}
|
|
1996
2056
|
}
|
|
1997
2057
|
catch {
|
|
1998
2058
|
this.#resolveErrored = true;
|
|
@@ -2005,7 +2065,15 @@ class State extends Contract {
|
|
|
2005
2065
|
if (!this.shouldSync) {
|
|
2006
2066
|
return;
|
|
2007
2067
|
}
|
|
2008
|
-
|
|
2068
|
+
try {
|
|
2069
|
+
if (this.jobber.busy && this.jobber.stop) {
|
|
2070
|
+
await this.jobber.stop();
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
catch (error) {
|
|
2074
|
+
console.error(error);
|
|
2075
|
+
}
|
|
2076
|
+
// await queue.clear()
|
|
2009
2077
|
this.#chainSyncing = true;
|
|
2010
2078
|
if (!lastBlock)
|
|
2011
2079
|
lastBlock = await this.#getLatestBlock();
|
|
@@ -2033,9 +2101,9 @@ class State extends Contract {
|
|
|
2033
2101
|
}
|
|
2034
2102
|
async #syncChain(lastBlock) {
|
|
2035
2103
|
try {
|
|
2036
|
-
if (this
|
|
2104
|
+
if (this.knownBlocks?.length === Number(lastBlock.index) + 1) {
|
|
2037
2105
|
let promises = [];
|
|
2038
|
-
promises = await Promise.allSettled(this
|
|
2106
|
+
promises = await Promise.allSettled(this.knownBlocks.map(async (address) => {
|
|
2039
2107
|
const has = await globalThis.peernet.has(address, 'block');
|
|
2040
2108
|
return { has, address };
|
|
2041
2109
|
}));
|
|
@@ -2067,15 +2135,16 @@ class State extends Contract {
|
|
|
2067
2135
|
let node = await globalThis.peernet.prepareMessage(data);
|
|
2068
2136
|
for (const peer of globalThis.peernet?.connections) {
|
|
2069
2137
|
if (peer.connected && peer.version === this.version) {
|
|
2070
|
-
|
|
2138
|
+
const task = async () => {
|
|
2071
2139
|
try {
|
|
2072
2140
|
const result = await peer.request(node.encoded);
|
|
2073
|
-
return { result, peer };
|
|
2141
|
+
return { result: Uint8Array.from(Object.values(result)), peer };
|
|
2074
2142
|
}
|
|
2075
2143
|
catch (error) {
|
|
2076
2144
|
throw error;
|
|
2077
2145
|
}
|
|
2078
|
-
}
|
|
2146
|
+
};
|
|
2147
|
+
promises.push(task());
|
|
2079
2148
|
}
|
|
2080
2149
|
}
|
|
2081
2150
|
promises = await this.promiseRequests(promises);
|
|
@@ -2096,7 +2165,7 @@ class State extends Contract {
|
|
|
2096
2165
|
let node = await globalThis.peernet.prepareMessage(data);
|
|
2097
2166
|
let message = await peer.request(node);
|
|
2098
2167
|
message = await new globalThis.peernet.protos['peernet-response'](message);
|
|
2099
|
-
this
|
|
2168
|
+
this.knownBlocks = message.decoded.response;
|
|
2100
2169
|
}
|
|
2101
2170
|
}
|
|
2102
2171
|
return latest;
|
|
@@ -2109,6 +2178,8 @@ class State extends Contract {
|
|
|
2109
2178
|
let poolTransactionKeys = await globalThis.transactionPoolStore.keys();
|
|
2110
2179
|
for (const block of blocks) {
|
|
2111
2180
|
if (block && !block.loaded) {
|
|
2181
|
+
if (block.index === 0)
|
|
2182
|
+
this.#loaded = true;
|
|
2112
2183
|
for (const transaction of block.transactions) {
|
|
2113
2184
|
if (poolTransactionKeys.includes(transaction.hash))
|
|
2114
2185
|
await globalThis.transactionPoolStore.delete(transaction.hash);
|
|
@@ -2147,7 +2218,8 @@ class State extends Contract {
|
|
|
2147
2218
|
clearTimeout(timeout);
|
|
2148
2219
|
if (promises.length > 0) {
|
|
2149
2220
|
promises = promises.map(async ({ value }) => {
|
|
2150
|
-
|
|
2221
|
+
console.log(value);
|
|
2222
|
+
const node = await new globalThis.peernet.protos['peernet-response'](value.result);
|
|
2151
2223
|
return { value: node.decoded.response, peer: value.peer };
|
|
2152
2224
|
});
|
|
2153
2225
|
promises = await Promise.all(promises);
|
|
@@ -2325,8 +2397,8 @@ class Chain extends State {
|
|
|
2325
2397
|
return;
|
|
2326
2398
|
const lastBlock = await this.#makeRequest(peer, 'lastBlock');
|
|
2327
2399
|
if (Object.keys(lastBlock).length > 0) {
|
|
2328
|
-
if (!this.lastBlock || !this.blocks[this.blocks.length - 1]
|
|
2329
|
-
|
|
2400
|
+
if (!this.lastBlock || !this.blocks[this.blocks.length - 1]?.loaded || lastBlock && lastBlock.index > this.lastBlock?.index || !this.loaded && !this.resolving) {
|
|
2401
|
+
this.knownBlocks = await this.#makeRequest(peer, 'knownBlocks');
|
|
2330
2402
|
await this.syncChain(lastBlock);
|
|
2331
2403
|
// if (await this.hasTransactionToHandle() && this.#participating) this.#runEpoch()
|
|
2332
2404
|
}
|
package/exports/chain.js
CHANGED
|
@@ -444,7 +444,33 @@ class Machine {
|
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
-
|
|
447
|
+
class Jobber {
|
|
448
|
+
timeout;
|
|
449
|
+
busy = false;
|
|
450
|
+
stop;
|
|
451
|
+
constructor(timeout) {
|
|
452
|
+
this.timeout = timeout;
|
|
453
|
+
}
|
|
454
|
+
add(fn) {
|
|
455
|
+
this.busy = true;
|
|
456
|
+
return new Promise(async (resolve, reject) => {
|
|
457
|
+
const timeout = setTimeout(() => {
|
|
458
|
+
reject('timeout');
|
|
459
|
+
}, this.timeout);
|
|
460
|
+
this.stop = () => {
|
|
461
|
+
clearTimeout(timeout);
|
|
462
|
+
this.busy = false;
|
|
463
|
+
resolve('stopped');
|
|
464
|
+
};
|
|
465
|
+
const result = await fn();
|
|
466
|
+
clearTimeout(timeout);
|
|
467
|
+
this.busy = false;
|
|
468
|
+
resolve(result);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
new PQueue({ concurrency: 1, throwOnTimeout: true });
|
|
448
474
|
class State extends Contract {
|
|
449
475
|
#resolveErrored;
|
|
450
476
|
#lastResolvedTime;
|
|
@@ -458,9 +484,16 @@ class State extends Contract {
|
|
|
458
484
|
#chainSyncing = false;
|
|
459
485
|
#lastBlock = { index: 0, hash: '0x0', previousHash: '0x0' };
|
|
460
486
|
#blocks = [];
|
|
461
|
-
|
|
487
|
+
knownBlocks = [];
|
|
462
488
|
#totalSize = 0;
|
|
463
489
|
#machine;
|
|
490
|
+
#loaded = false;
|
|
491
|
+
get loaded() {
|
|
492
|
+
return this.#loaded;
|
|
493
|
+
}
|
|
494
|
+
get resolving() {
|
|
495
|
+
return this.#resolving;
|
|
496
|
+
}
|
|
464
497
|
/**
|
|
465
498
|
* amount the native token has been iteracted with
|
|
466
499
|
*/
|
|
@@ -515,6 +548,7 @@ class State extends Contract {
|
|
|
515
548
|
super();
|
|
516
549
|
}
|
|
517
550
|
async init() {
|
|
551
|
+
this.jobber = new Jobber(30_000);
|
|
518
552
|
if (super.init)
|
|
519
553
|
await super.init();
|
|
520
554
|
await globalThis.peernet.addRequestHandler('lastBlock', this.#lastBlockHandler.bind(this));
|
|
@@ -587,18 +621,27 @@ class State extends Contract {
|
|
|
587
621
|
return;
|
|
588
622
|
}
|
|
589
623
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
624
|
+
try {
|
|
625
|
+
const block = await this.getAndPutBlock(hash);
|
|
626
|
+
index = block.decoded.index;
|
|
627
|
+
const size = block.encoded.length > 0 ? block.encoded.length : block.encoded.byteLength;
|
|
628
|
+
this.#totalSize += size;
|
|
629
|
+
this.#blocks[index] = { hash, ...block.decoded };
|
|
630
|
+
this.#blockHashMap.set(hash, index);
|
|
631
|
+
globalThis.debug(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
|
|
632
|
+
this.#lastResolved = this.#blocks[index];
|
|
633
|
+
this.#lastResolvedTime = Date.now();
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
this.#resolving = false;
|
|
637
|
+
this.#chainSyncing = false;
|
|
638
|
+
throw new Error('resolve error');
|
|
639
|
+
}
|
|
599
640
|
return;
|
|
600
641
|
}
|
|
601
642
|
async resolveBlock(hash) {
|
|
643
|
+
if (this.#resolveErrorCount === 3)
|
|
644
|
+
this.#resolveErrorCount = 0;
|
|
602
645
|
if (!hash)
|
|
603
646
|
throw new Error(`expected hash, got: ${hash}`);
|
|
604
647
|
if (hash === '0x0')
|
|
@@ -606,19 +649,36 @@ class State extends Contract {
|
|
|
606
649
|
if (this.#resolving)
|
|
607
650
|
return 'already resolving';
|
|
608
651
|
this.#resolving = true;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
652
|
+
try {
|
|
653
|
+
await this.jobber.add(() => this.#resolveBlock(hash));
|
|
654
|
+
this.#resolving = false;
|
|
655
|
+
if (!this.#blockHashMap.has(this.#lastResolved.previousHash) && this.#lastResolved.previousHash !== '0x0')
|
|
656
|
+
return this.resolveBlock(this.#lastResolved.previousHash);
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
this.#resolveErrorCount += 1;
|
|
660
|
+
if (this.#resolveErrorCount < 3)
|
|
661
|
+
return this.resolveBlock(hash);
|
|
662
|
+
else
|
|
663
|
+
throw new Error('resolve errored');
|
|
664
|
+
}
|
|
614
665
|
}
|
|
615
666
|
async resolveBlocks() {
|
|
667
|
+
try {
|
|
668
|
+
if (this.jobber.busy && this.jobber.stop) {
|
|
669
|
+
await this.jobber.stop();
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
console.error(error);
|
|
674
|
+
}
|
|
616
675
|
try {
|
|
617
676
|
const localBlock = await globalThis.chainStore.get('lastBlock');
|
|
618
677
|
const hash = new TextDecoder().decode(localBlock);
|
|
619
|
-
if (hash && hash !== '0x0')
|
|
678
|
+
if (hash && hash !== '0x0') {
|
|
620
679
|
await this.resolveBlock(hash);
|
|
621
|
-
|
|
680
|
+
this.#lastBlock = this.#blocks[this.#blocks.length - 1];
|
|
681
|
+
}
|
|
622
682
|
}
|
|
623
683
|
catch {
|
|
624
684
|
this.#resolveErrored = true;
|
|
@@ -631,7 +691,15 @@ class State extends Contract {
|
|
|
631
691
|
if (!this.shouldSync) {
|
|
632
692
|
return;
|
|
633
693
|
}
|
|
634
|
-
|
|
694
|
+
try {
|
|
695
|
+
if (this.jobber.busy && this.jobber.stop) {
|
|
696
|
+
await this.jobber.stop();
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
console.error(error);
|
|
701
|
+
}
|
|
702
|
+
// await queue.clear()
|
|
635
703
|
this.#chainSyncing = true;
|
|
636
704
|
if (!lastBlock)
|
|
637
705
|
lastBlock = await this.#getLatestBlock();
|
|
@@ -659,9 +727,9 @@ class State extends Contract {
|
|
|
659
727
|
}
|
|
660
728
|
async #syncChain(lastBlock) {
|
|
661
729
|
try {
|
|
662
|
-
if (this
|
|
730
|
+
if (this.knownBlocks?.length === Number(lastBlock.index) + 1) {
|
|
663
731
|
let promises = [];
|
|
664
|
-
promises = await Promise.allSettled(this
|
|
732
|
+
promises = await Promise.allSettled(this.knownBlocks.map(async (address) => {
|
|
665
733
|
const has = await globalThis.peernet.has(address, 'block');
|
|
666
734
|
return { has, address };
|
|
667
735
|
}));
|
|
@@ -693,15 +761,16 @@ class State extends Contract {
|
|
|
693
761
|
let node = await globalThis.peernet.prepareMessage(data);
|
|
694
762
|
for (const peer of globalThis.peernet?.connections) {
|
|
695
763
|
if (peer.connected && peer.version === this.version) {
|
|
696
|
-
|
|
764
|
+
const task = async () => {
|
|
697
765
|
try {
|
|
698
766
|
const result = await peer.request(node.encoded);
|
|
699
|
-
return { result, peer };
|
|
767
|
+
return { result: Uint8Array.from(Object.values(result)), peer };
|
|
700
768
|
}
|
|
701
769
|
catch (error) {
|
|
702
770
|
throw error;
|
|
703
771
|
}
|
|
704
|
-
}
|
|
772
|
+
};
|
|
773
|
+
promises.push(task());
|
|
705
774
|
}
|
|
706
775
|
}
|
|
707
776
|
promises = await this.promiseRequests(promises);
|
|
@@ -722,7 +791,7 @@ class State extends Contract {
|
|
|
722
791
|
let node = await globalThis.peernet.prepareMessage(data);
|
|
723
792
|
let message = await peer.request(node);
|
|
724
793
|
message = await new globalThis.peernet.protos['peernet-response'](message);
|
|
725
|
-
this
|
|
794
|
+
this.knownBlocks = message.decoded.response;
|
|
726
795
|
}
|
|
727
796
|
}
|
|
728
797
|
return latest;
|
|
@@ -735,6 +804,8 @@ class State extends Contract {
|
|
|
735
804
|
let poolTransactionKeys = await globalThis.transactionPoolStore.keys();
|
|
736
805
|
for (const block of blocks) {
|
|
737
806
|
if (block && !block.loaded) {
|
|
807
|
+
if (block.index === 0)
|
|
808
|
+
this.#loaded = true;
|
|
738
809
|
for (const transaction of block.transactions) {
|
|
739
810
|
if (poolTransactionKeys.includes(transaction.hash))
|
|
740
811
|
await globalThis.transactionPoolStore.delete(transaction.hash);
|
|
@@ -773,7 +844,8 @@ class State extends Contract {
|
|
|
773
844
|
clearTimeout(timeout);
|
|
774
845
|
if (promises.length > 0) {
|
|
775
846
|
promises = promises.map(async ({ value }) => {
|
|
776
|
-
|
|
847
|
+
console.log(value);
|
|
848
|
+
const node = await new globalThis.peernet.protos['peernet-response'](value.result);
|
|
777
849
|
return { value: node.decoded.response, peer: value.peer };
|
|
778
850
|
});
|
|
779
851
|
promises = await Promise.all(promises);
|
|
@@ -951,8 +1023,8 @@ class Chain extends State {
|
|
|
951
1023
|
return;
|
|
952
1024
|
const lastBlock = await this.#makeRequest(peer, 'lastBlock');
|
|
953
1025
|
if (Object.keys(lastBlock).length > 0) {
|
|
954
|
-
if (!this.lastBlock || !this.blocks[this.blocks.length - 1]
|
|
955
|
-
|
|
1026
|
+
if (!this.lastBlock || !this.blocks[this.blocks.length - 1]?.loaded || lastBlock && lastBlock.index > this.lastBlock?.index || !this.loaded && !this.resolving) {
|
|
1027
|
+
this.knownBlocks = await this.#makeRequest(peer, 'knownBlocks');
|
|
956
1028
|
await this.syncChain(lastBlock);
|
|
957
1029
|
// if (await this.hasTransactionToHandle() && this.#participating) this.#runEpoch()
|
|
958
1030
|
}
|
package/package.json
CHANGED