@leofcoin/chain 1.10.20 → 1.10.22
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/README.md +38 -0
- package/exports/browser/beacon-wire.js +1 -1
- package/exports/browser/{browser-CCfR9KOM-BGMMnVsR.js → browser-CCfR9KOM-UO9mzy-j.js} +2 -2
- package/exports/browser/chain.js +98 -165
- package/exports/browser/client-DbZBfpG6-CYDyUGUC.js +5943 -0
- package/exports/browser/{connection-monitor-D-krNiRH.js → connection-monitor-DMGAhcC0.js} +111 -2
- package/exports/browser/{index-dTQVgkpf-DOL2rIjp.js → index-dTQVgkpf-C6SJ0ZYW.js} +2 -2
- package/exports/browser/{index-DCbLvMKL.js → index-dxD17Fom.js} +231 -227
- package/exports/browser/{messages-DCePyqKC-BSvJxDWZ.js → messages-DZYCxoZI-D6kIiLKF.js} +2 -2
- package/exports/browser/{node-browser-Ha4Lvntj.js → node-browser-BMfelxXV.js} +23 -7
- package/exports/browser/node-browser.js +2 -2
- package/exports/chain.js +97 -164
- package/exports/connection-monitor-h2L8vsS7.js +435 -0
- package/exports/connection-monitor.js +2 -324
- package/exports/node.js +3 -1
- package/package.json +6 -6
- package/exports/browser/client-DKKzPSlb-C_1ug6ux.js +0 -2401
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { F as FormatInterface } from './node-browser-
|
|
1
|
+
import { F as FormatInterface } from './node-browser-BMfelxXV.js';
|
|
2
2
|
import './browser-crypto-CH0ua22L.js';
|
|
3
|
-
import './connection-monitor-
|
|
3
|
+
import './connection-monitor-DMGAhcC0.js';
|
|
4
4
|
import './index-CvKt4UDE.js';
|
|
5
5
|
import './sha2-BKcEJzgd.js';
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { F as FormatInterface$2, T as TransactionMessage, C as ContractMessage, n as createHash$1 } from './browser-crypto-CH0ua22L.js';
|
|
2
|
-
import { B as BlockMessage,
|
|
2
|
+
import { B as BlockMessage, b as BWMessage, V as ValidatorMessage, S as StateMessage, L as LastBlockMessage, D as DEFAULT_NODE_OPTIONS, g as guardPeerMessages, c as guardProviderDiscovery } from './connection-monitor-DMGAhcC0.js';
|
|
3
3
|
import './index-CvKt4UDE.js';
|
|
4
4
|
|
|
5
5
|
var proto = {};
|
|
@@ -8510,7 +8510,7 @@ class Identity {
|
|
|
8510
8510
|
this.selectedAccount = new TextDecoder().decode(selected);
|
|
8511
8511
|
}
|
|
8512
8512
|
else {
|
|
8513
|
-
const importee = await import(/* webpackChunkName: "generate-account" */ './index-dTQVgkpf-
|
|
8513
|
+
const importee = await import(/* webpackChunkName: "generate-account" */ './index-dTQVgkpf-C6SJ0ZYW.js');
|
|
8514
8514
|
const { identity, accounts } = await importee.default(password, this.network);
|
|
8515
8515
|
if (fresh) {
|
|
8516
8516
|
await globalThis.accountStore.clear();
|
|
@@ -16102,7 +16102,7 @@ const blockchainCodecs = [
|
|
|
16102
16102
|
},
|
|
16103
16103
|
{
|
|
16104
16104
|
name: 'raw-transaction-message',
|
|
16105
|
-
codec: '
|
|
16105
|
+
codec: '0x72746d',
|
|
16106
16106
|
hashAlg: 'keccak-256'
|
|
16107
16107
|
},
|
|
16108
16108
|
{
|
|
@@ -16147,6 +16147,21 @@ const blockchainCodecs = [
|
|
|
16147
16147
|
}
|
|
16148
16148
|
];
|
|
16149
16149
|
const consensusCodecs = [
|
|
16150
|
+
{
|
|
16151
|
+
name: 'beacon-activation-message',
|
|
16152
|
+
codec: '0x62616d',
|
|
16153
|
+
hashAlg: 'keccak-256'
|
|
16154
|
+
},
|
|
16155
|
+
{
|
|
16156
|
+
name: 'beacon-commitment-message',
|
|
16157
|
+
codec: '0x62636d',
|
|
16158
|
+
hashAlg: 'keccak-256'
|
|
16159
|
+
},
|
|
16160
|
+
{
|
|
16161
|
+
name: 'beacon-share-message',
|
|
16162
|
+
codec: '0x62736d',
|
|
16163
|
+
hashAlg: 'keccak-256'
|
|
16164
|
+
},
|
|
16150
16165
|
{
|
|
16151
16166
|
name: 'proposal-message',
|
|
16152
16167
|
codec: '0x70726d',
|
|
@@ -16225,7 +16240,7 @@ const peernetCodecs = [
|
|
|
16225
16240
|
},
|
|
16226
16241
|
{
|
|
16227
16242
|
name: 'peernet-ps',
|
|
16228
|
-
codec: '
|
|
16243
|
+
codec: '0x707073',
|
|
16229
16244
|
hashAlg: 'keccak-256'
|
|
16230
16245
|
},
|
|
16231
16246
|
{
|
|
@@ -17927,7 +17942,7 @@ class Peernet {
|
|
|
17927
17942
|
await getAddress();
|
|
17928
17943
|
this.storePrefix = options.storePrefix;
|
|
17929
17944
|
this.root = options.root;
|
|
17930
|
-
const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile } = await import(/* webpackChunkName: "messages" */ './messages-
|
|
17945
|
+
const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile } = await import(/* webpackChunkName: "messages" */ './messages-DZYCxoZI-D6kIiLKF.js');
|
|
17931
17946
|
/**
|
|
17932
17947
|
* proto Object containing protos
|
|
17933
17948
|
* @type {Object}
|
|
@@ -17973,7 +17988,7 @@ class Peernet {
|
|
|
17973
17988
|
if (this.#starting || this.#started)
|
|
17974
17989
|
return;
|
|
17975
17990
|
this.#starting = true;
|
|
17976
|
-
const importee = await import('./client-
|
|
17991
|
+
const importee = await import('./client-DbZBfpG6-CYDyUGUC.js');
|
|
17977
17992
|
/**
|
|
17978
17993
|
* @access public
|
|
17979
17994
|
* @type {PeernetClient}
|
|
@@ -18776,6 +18791,7 @@ class Node {
|
|
|
18776
18791
|
config = { ...DEFAULT_NODE_OPTIONS, ...config };
|
|
18777
18792
|
this.#node = globalThis.Peernet ? await new globalThis.Peernet(config, password) : await new Peernet(config, password);
|
|
18778
18793
|
guardPeerMessages(this.#node);
|
|
18794
|
+
guardProviderDiscovery(this.#node);
|
|
18779
18795
|
await nodeConfig(config);
|
|
18780
18796
|
globalThis.pubsub.subscribe("chain:ready", async () => {
|
|
18781
18797
|
if (!this.#node.autoStart) {
|
|
@@ -18787,4 +18803,4 @@ class Node {
|
|
|
18787
18803
|
}
|
|
18788
18804
|
}
|
|
18789
18805
|
|
|
18790
|
-
export { FormatInterface as F, LittlePubSub as L, MultiWallet as M, Node as N, base58$1 as b, createDebugger as c,
|
|
18806
|
+
export { FormatInterface as F, LittlePubSub as L, MultiWallet as M, Node as N, base58$1 as b, createDebugger as c, encrypt as e, getDefaultExportFromCjs as g };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { N as default } from './node-browser-
|
|
1
|
+
export { N as default } from './node-browser-BMfelxXV.js';
|
|
2
2
|
import './browser-crypto-CH0ua22L.js';
|
|
3
|
-
import './connection-monitor-
|
|
3
|
+
import './connection-monitor-DMGAhcC0.js';
|
|
4
4
|
import './index-CvKt4UDE.js';
|
|
5
5
|
import './sha2-BKcEJzgd.js';
|
package/exports/chain.js
CHANGED
|
@@ -7,39 +7,16 @@ import { MAX_TRANSACTION_BYTES, MAX_BLOCK_TRANSACTION_BYTES, MAX_BLOCK_TRANSACTI
|
|
|
7
7
|
import MultiWallet from '@leofcoin/multi-wallet';
|
|
8
8
|
import { fromBase58 } from '@vandeurenglenn/typed-array-utils';
|
|
9
9
|
import semver from 'semver';
|
|
10
|
+
import { P as Protocol, C as ConnectionMonitor } from './connection-monitor-h2L8vsS7.js';
|
|
10
11
|
import { randombytes } from '@leofcoin/crypto';
|
|
11
12
|
import EasyWorker from '@vandeurenglenn/easy-worker';
|
|
12
13
|
import { ContractDeploymentError, ExecutionError, isResolveError, ResolveError, isExecutionError } from '@leofcoin/errors';
|
|
13
14
|
import { P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO } from './constants-Dy9i9S_o.js';
|
|
14
|
-
import ConnectionMonitor from './connection-monitor.js';
|
|
15
15
|
import { q as quorumThreshold } from './quorum-S_qdgiAY.js';
|
|
16
16
|
import { assertHashFormatState } from './hash-format-state.js';
|
|
17
17
|
import { createChainIdentity, assertChainId, findChainPresence } from '@leofcoin/lib/chain-identity';
|
|
18
18
|
import '@leofcoin/networks';
|
|
19
19
|
|
|
20
|
-
const limit = 1800;
|
|
21
|
-
const transactionLimit = 2500;
|
|
22
|
-
const requestTimeout = 3e4;
|
|
23
|
-
const syncTimeout = 3e4;
|
|
24
|
-
class Protocol {
|
|
25
|
-
constructor(config) {
|
|
26
|
-
this.resolveTimeout = 1e4;
|
|
27
|
-
if (config?.resolveTimeout) this.resolveTimeout = config.resolveTimeout;
|
|
28
|
-
}
|
|
29
|
-
get limit() {
|
|
30
|
-
return limit;
|
|
31
|
-
}
|
|
32
|
-
get transactionLimit() {
|
|
33
|
-
return transactionLimit;
|
|
34
|
-
}
|
|
35
|
-
get requestTimeout() {
|
|
36
|
-
return requestTimeout;
|
|
37
|
-
}
|
|
38
|
-
get syncTimeout() {
|
|
39
|
-
return syncTimeout;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
20
|
const waitForCanonicalTransaction = (pubsub, transactionPool, hash) => new Promise((resolve, reject) => {
|
|
44
21
|
const completionTopic = `transaction.completed.${hash}`;
|
|
45
22
|
const cleanup = () => {
|
|
@@ -266,7 +243,7 @@ class Transaction extends Protocol {
|
|
|
266
243
|
await globalThis.transactionPoolStore.put(hash, message.encoded);
|
|
267
244
|
this.addPendingNonce(message.decoded.from, message.decoded.nonce);
|
|
268
245
|
try {
|
|
269
|
-
peernet.publish("add-transaction", message.encoded);
|
|
246
|
+
await peernet.publish("add-transaction", message.encoded);
|
|
270
247
|
} catch (publishError) {
|
|
271
248
|
console.warn("peernet publish failed: add-transaction", publishError?.message ?? publishError);
|
|
272
249
|
}
|
|
@@ -1267,6 +1244,15 @@ const validateChainLink = (localTip, incoming) => {
|
|
|
1267
1244
|
return "append";
|
|
1268
1245
|
};
|
|
1269
1246
|
|
|
1247
|
+
const resolveTransactionReference = async (expectedHash, transactionData) => {
|
|
1248
|
+
const transaction = transactionData instanceof TransactionMessage ? transactionData : new TransactionMessage(transactionData);
|
|
1249
|
+
const actualHash = await transaction.hash();
|
|
1250
|
+
if (actualHash !== expectedHash) {
|
|
1251
|
+
throw new Error(`Transaction hash mismatch: expected ${expectedHash}, got ${actualHash}`);
|
|
1252
|
+
}
|
|
1253
|
+
return transaction;
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1270
1256
|
const debug$1 = createDebugger("leofcoin/state");
|
|
1271
1257
|
class State extends Contract {
|
|
1272
1258
|
constructor(config) {
|
|
@@ -1283,7 +1269,7 @@ class State extends Contract {
|
|
|
1283
1269
|
this.#totalSize = 0;
|
|
1284
1270
|
this.#canonicalStateQueue = new CanonicalStateQueue();
|
|
1285
1271
|
this.#loaded = false;
|
|
1286
|
-
this.#resolvingHashes = /* @__PURE__ */ new
|
|
1272
|
+
this.#resolvingHashes = /* @__PURE__ */ new Map();
|
|
1287
1273
|
this._wantList = [];
|
|
1288
1274
|
this.#chainStateHandler = () => {
|
|
1289
1275
|
return new globalThis.peernet.protos["peernet-response"]({
|
|
@@ -1539,7 +1525,8 @@ class State extends Contract {
|
|
|
1539
1525
|
if (!exists) {
|
|
1540
1526
|
const data = await peernet.get(hash, "transaction");
|
|
1541
1527
|
if (!data) throw new Error(`missing transaction data for ${hash}`);
|
|
1542
|
-
await
|
|
1528
|
+
const transaction = await resolveTransactionReference(hash, data);
|
|
1529
|
+
await transactionStore.put(hash, transaction.encoded);
|
|
1543
1530
|
}
|
|
1544
1531
|
const inPool = await transactionPoolStore.has(hash);
|
|
1545
1532
|
if (inPool) await transactionPoolStore.delete(hash);
|
|
@@ -1547,84 +1534,61 @@ class State extends Contract {
|
|
|
1547
1534
|
);
|
|
1548
1535
|
}
|
|
1549
1536
|
async #resolveBlock(hash) {
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1537
|
+
const localHash = (await this.canonicalTip()).hash;
|
|
1538
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1539
|
+
while (hash !== "0x0" && hash !== localHash) {
|
|
1540
|
+
if (visited.has(hash)) throw new ResolveError(`cyclic block ancestry at ${hash}`);
|
|
1541
|
+
visited.add(hash);
|
|
1542
|
+
const cachedIndex = this.#blockHashMap.get(hash);
|
|
1543
|
+
const cached = this.#blocks[cachedIndex];
|
|
1544
|
+
if (cached) {
|
|
1545
|
+
hash = cached.previousHash;
|
|
1546
|
+
continue;
|
|
1557
1547
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1548
|
+
try {
|
|
1549
|
+
const block = await this.getAndPutBlock(hash);
|
|
1550
|
+
await this.#resolveTransactions(block.decoded.transactions);
|
|
1551
|
+
const index = block.decoded.index;
|
|
1552
|
+
const size = block.encoded.byteLength;
|
|
1553
|
+
this.#totalSize += size;
|
|
1554
|
+
this.#blocks[index] = { hash, ...block.decoded };
|
|
1555
|
+
this.#blockHashMap.set(hash, index);
|
|
1556
|
+
debug$1(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
|
|
1557
|
+
globalThis.pubsub.publish("block-resolved", { hash, index });
|
|
1558
|
+
this.#lastResolved = this.#blocks[index];
|
|
1559
|
+
this.#lastResolvedTime = Date.now();
|
|
1560
|
+
hash = block.decoded.previousHash;
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
throw new ResolveError(`block: ${hash}`, { cause: error });
|
|
1568
1563
|
}
|
|
1569
1564
|
}
|
|
1570
|
-
try {
|
|
1571
|
-
const block = await this.getAndPutBlock(hash);
|
|
1572
|
-
const promises = [];
|
|
1573
|
-
if (block.decoded.previousHash !== "0x0" && block.decoded.previousHash !== localHash) {
|
|
1574
|
-
promises.push(this.resolveBlock(block.decoded.previousHash));
|
|
1575
|
-
}
|
|
1576
|
-
promises.push(this.#resolveTransactions(block.decoded.transactions));
|
|
1577
|
-
await Promise.all(promises);
|
|
1578
|
-
index = block.decoded.index;
|
|
1579
|
-
const size = block.encoded.length > 0 ? block.encoded.length : block.encoded.byteLength;
|
|
1580
|
-
this.#totalSize += size;
|
|
1581
|
-
this.#blocks[index] = { hash, ...block.decoded };
|
|
1582
|
-
this.#blockHashMap.set(hash, index);
|
|
1583
|
-
debug$1(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
|
|
1584
|
-
globalThis.pubsub.publish("block-resolved", { hash, index });
|
|
1585
|
-
this.#lastResolved = this.#blocks[index];
|
|
1586
|
-
this.#lastResolvedTime = Date.now();
|
|
1587
|
-
} catch (error) {
|
|
1588
|
-
throw new ResolveError(`block: ${hash}@${index}`, { cause: error });
|
|
1589
|
-
}
|
|
1590
|
-
return;
|
|
1591
1565
|
}
|
|
1592
1566
|
async resolveBlock(hash) {
|
|
1593
1567
|
if (!hash) throw new Error(`expected hash, got: ${hash}`);
|
|
1594
1568
|
if (hash === "0x0") return;
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
const isEntering = this.#resolvingHashes.size === 1;
|
|
1569
|
+
const existing = this.#resolvingHashes.get(hash);
|
|
1570
|
+
if (existing) return existing;
|
|
1598
1571
|
this.#resolving = true;
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
} else {
|
|
1604
|
-
await this.#resolveBlock(hash);
|
|
1605
|
-
}
|
|
1606
|
-
try {
|
|
1607
|
-
const lastBlockHash = await globalThis.stateStore.get("lastBlock");
|
|
1608
|
-
if (lastBlockHash === hash) {
|
|
1572
|
+
const resolution = Promise.resolve().then(async () => {
|
|
1573
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1574
|
+
try {
|
|
1575
|
+
await this.#resolveBlock(hash);
|
|
1609
1576
|
this.#resolveErrored = false;
|
|
1610
1577
|
return;
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
console.error(`block resolution attempt ${attempt + 1} failed for ${hash}`, error);
|
|
1580
|
+
if (attempt === 2) {
|
|
1581
|
+
if (!this.wantList.includes(hash)) this.wantList.push(hash);
|
|
1582
|
+
throw new ResolveError(`block: ${hash}`, { cause: error });
|
|
1583
|
+
}
|
|
1611
1584
|
}
|
|
1612
|
-
} catch (error) {
|
|
1613
1585
|
}
|
|
1614
|
-
}
|
|
1615
|
-
console.log({ error });
|
|
1616
|
-
this.#resolveErrorCount += 1;
|
|
1617
|
-
if (this.#resolveErrorCount < 3) {
|
|
1618
|
-
this.#resolvingHashes.delete(hash);
|
|
1619
|
-
return this.resolveBlock(hash);
|
|
1620
|
-
}
|
|
1621
|
-
this.#resolveErrorCount = 0;
|
|
1622
|
-
this.wantList.push(hash);
|
|
1623
|
-
throw new ResolveError(`block: ${hash}`, { cause: error });
|
|
1624
|
-
} finally {
|
|
1586
|
+
}).finally(() => {
|
|
1625
1587
|
this.#resolvingHashes.delete(hash);
|
|
1626
1588
|
if (this.#resolvingHashes.size === 0) this.#resolving = false;
|
|
1627
|
-
}
|
|
1589
|
+
});
|
|
1590
|
+
this.#resolvingHashes.set(hash, resolution);
|
|
1591
|
+
return resolution;
|
|
1628
1592
|
}
|
|
1629
1593
|
async resolveBlocks() {
|
|
1630
1594
|
if (this.#chainSyncing || this.#resolving) {
|
|
@@ -1761,24 +1725,6 @@ class State extends Contract {
|
|
|
1761
1725
|
return;
|
|
1762
1726
|
}
|
|
1763
1727
|
if (localStateHash !== remoteBlockHash) {
|
|
1764
|
-
if (this.wantList.length > 0) {
|
|
1765
|
-
debug$1(`Fetching ${this.wantList.length} blocks before resolving`);
|
|
1766
|
-
const getBatch = async (batch) => {
|
|
1767
|
-
const blocks2 = await Promise.all(
|
|
1768
|
-
batch.map(
|
|
1769
|
-
(hash) => this.getAndPutBlock(hash).catch((e) => {
|
|
1770
|
-
console.warn(`failed to fetch block ${hash}`, e);
|
|
1771
|
-
})
|
|
1772
|
-
)
|
|
1773
|
-
);
|
|
1774
|
-
const transactions = blocks2.filter((block) => Boolean(block)).flatMap((block) => block.decoded.transactions);
|
|
1775
|
-
return this.#resolveTransactions(transactions);
|
|
1776
|
-
};
|
|
1777
|
-
for (let i = 0; i < this.wantList.length; i += 50) {
|
|
1778
|
-
const batch = this.wantList.slice(i, i + 50);
|
|
1779
|
-
await getBatch(batch);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
1728
|
debug$1(`Resolving remote block: ${remoteBlockHash} @${remoteIndex} (differs from local state)`);
|
|
1783
1729
|
await this.resolveBlock(remoteBlockHash);
|
|
1784
1730
|
const blocksSynced = remoteIndex - localIndex;
|
|
@@ -2134,15 +2080,6 @@ const validateBlockEconomics = (block, calculatedFees, validatorFees = /* @__PUR
|
|
|
2134
2080
|
}
|
|
2135
2081
|
};
|
|
2136
2082
|
|
|
2137
|
-
const resolveTransactionReference = async (expectedHash, transactionData) => {
|
|
2138
|
-
const transaction = transactionData instanceof TransactionMessage ? transactionData : new TransactionMessage(transactionData);
|
|
2139
|
-
const actualHash = await transaction.hash();
|
|
2140
|
-
if (actualHash !== expectedHash) {
|
|
2141
|
-
throw new Error(`Transaction hash mismatch: expected ${expectedHash}, got ${actualHash}`);
|
|
2142
|
-
}
|
|
2143
|
-
return transaction;
|
|
2144
|
-
};
|
|
2145
|
-
|
|
2146
2083
|
const consensusSignableData = (validatorsAddress, type, message) => ({
|
|
2147
2084
|
from: String(message.from),
|
|
2148
2085
|
to: validatorsAddress,
|
|
@@ -2960,39 +2897,29 @@ class Chain extends VersionControl {
|
|
|
2960
2897
|
}
|
|
2961
2898
|
async getPeerTransactionPool(peer) {
|
|
2962
2899
|
let transactionsInPool = await this.#makeRequest(peer, "transactionPool");
|
|
2963
|
-
console.log("raw response for request transactionPool:", transactionsInPool);
|
|
2964
2900
|
if (transactionsInPool instanceof Uint8Array) {
|
|
2965
|
-
|
|
2966
|
-
transactionsInPool = JSON.parse(new TextDecoder().decode(transactionsInPool));
|
|
2967
|
-
} catch {
|
|
2968
|
-
debug("transactionPool response must be decoded array payload");
|
|
2969
|
-
return [];
|
|
2970
|
-
}
|
|
2901
|
+
transactionsInPool = new TextDecoder().decode(transactionsInPool);
|
|
2971
2902
|
}
|
|
2972
2903
|
if (typeof transactionsInPool === "string") {
|
|
2973
|
-
|
|
2974
|
-
transactionsInPool = JSON.parse(transactionsInPool);
|
|
2975
|
-
} catch {
|
|
2976
|
-
return [];
|
|
2977
|
-
}
|
|
2904
|
+
transactionsInPool = JSON.parse(transactionsInPool);
|
|
2978
2905
|
}
|
|
2979
|
-
if (!Array.isArray(transactionsInPool))
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
}
|
|
2906
|
+
if (!Array.isArray(transactionsInPool) || transactionsInPool.some((hash) => typeof hash !== "string")) {
|
|
2907
|
+
throw new Error("transactionPool response must be an array of transaction hashes");
|
|
2908
|
+
}
|
|
2909
|
+
const recovered = [];
|
|
2910
|
+
for (const hash of new Set(transactionsInPool)) {
|
|
2911
|
+
if (await globalThis.transactionPoolStore.has(hash)) continue;
|
|
2912
|
+
if (await globalThis.transactionStore.has(hash)) continue;
|
|
2913
|
+
try {
|
|
2914
|
+
const txData = await globalThis.peernet.get(hash, "transactionPool");
|
|
2915
|
+
if (txData === void 0) throw new Error("pending transaction body unavailable");
|
|
2916
|
+
const transaction = await resolveTransactionReference(hash, txData);
|
|
2917
|
+
recovered.push(await this.#sendTransaction(transaction));
|
|
2918
|
+
} catch (error) {
|
|
2919
|
+
debug(`Failed to recover transaction ${hash}:`, error?.message ?? error);
|
|
2993
2920
|
}
|
|
2994
2921
|
}
|
|
2995
|
-
return
|
|
2922
|
+
return recovered;
|
|
2996
2923
|
}
|
|
2997
2924
|
async #peerConnected(peerId) {
|
|
2998
2925
|
if (typeof peerId !== "string" || !peerId.trim() || peerId === "undefined") {
|
|
@@ -3060,6 +2987,14 @@ class Chain extends VersionControl {
|
|
|
3060
2987
|
await this.#recordPeerFailure(peerId, `unreasonable lastBlock index: ${lastBlock.index}`);
|
|
3061
2988
|
return;
|
|
3062
2989
|
}
|
|
2990
|
+
setTimeout(async () => {
|
|
2991
|
+
try {
|
|
2992
|
+
await this.getPeerTransactionPool(peer);
|
|
2993
|
+
} catch (error) {
|
|
2994
|
+
const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
|
|
2995
|
+
debug(`transactionPool request failed: ${peerName}:`, error?.message ?? error);
|
|
2996
|
+
}
|
|
2997
|
+
}, 3e3);
|
|
3063
2998
|
if (!lastBlock || !lastBlock.hash || lastBlock.hash === "0x0") {
|
|
3064
2999
|
debug(`peer has no lastBlock: ${peerId}`);
|
|
3065
3000
|
return;
|
|
@@ -3092,22 +3027,6 @@ class Chain extends VersionControl {
|
|
|
3092
3027
|
}
|
|
3093
3028
|
}
|
|
3094
3029
|
}
|
|
3095
|
-
if (this.wantList.length > 0) {
|
|
3096
|
-
const promises = await Promise.allSettled(this.wantList.map((hash) => peernet.get(hash, "block")));
|
|
3097
|
-
for (let i = promises.length - 1; i >= 0; i -= 1) {
|
|
3098
|
-
if (promises[i].status === "fulfilled") this.wantList.splice(i, 1);
|
|
3099
|
-
}
|
|
3100
|
-
if (this.wantList.length === 0) await this.triggerSync();
|
|
3101
|
-
}
|
|
3102
|
-
setTimeout(async () => {
|
|
3103
|
-
try {
|
|
3104
|
-
const peerTransactionPool = higherThenCurrentLocal && await this.getPeerTransactionPool(peer) || [];
|
|
3105
|
-
if (this.#participating && peerTransactionPool.length > 0) return this.#runEpoch();
|
|
3106
|
-
} catch (error) {
|
|
3107
|
-
const peerName = peer?.peerId || peer?.id || peer?.address || peerId || "unknown";
|
|
3108
|
-
debug(`transactionPool request failed: ${peerName}:`, error?.message ?? error);
|
|
3109
|
-
}
|
|
3110
|
-
}, 3e3);
|
|
3111
3030
|
try {
|
|
3112
3031
|
let stateInfo = await this.#makeRequest(peer, "stateInfo");
|
|
3113
3032
|
if (stateInfo instanceof Uint8Array) {
|
|
@@ -3484,18 +3403,32 @@ class Chain extends VersionControl {
|
|
|
3484
3403
|
await this.validateTransactionSignature(transaction);
|
|
3485
3404
|
let hash;
|
|
3486
3405
|
try {
|
|
3406
|
+
hash = await transaction.hash();
|
|
3407
|
+
if (await globalThis.transactionStore.has(hash)) return hash;
|
|
3408
|
+
const alreadyPending = await globalThis.transactionPoolStore.has(hash);
|
|
3487
3409
|
hash = await enqueueTransaction(transaction, {
|
|
3488
3410
|
putToPool: (txHash, data) => globalThis.transactionPoolStore.put(txHash, data),
|
|
3489
3411
|
hasInPool: (txHash) => globalThis.transactionPoolStore.has(txHash),
|
|
3490
3412
|
hasInStore: (txHash) => globalThis.transactionStore.has(txHash),
|
|
3491
3413
|
addPendingNonce: (address, nonce) => this.addPendingNonce(address, nonce)
|
|
3492
3414
|
});
|
|
3493
|
-
if (
|
|
3415
|
+
if (!alreadyPending) {
|
|
3416
|
+
try {
|
|
3417
|
+
await globalThis.peernet.publish("add-transaction", transaction.encoded);
|
|
3418
|
+
} catch (publishError) {
|
|
3419
|
+
debug("peernet publish failed: add-transaction relay", publishError?.message ?? publishError);
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
if (this.#participating && !this.#runningEpoch) {
|
|
3423
|
+
void this.#runEpoch().catch((error) => {
|
|
3424
|
+
debug("transaction epoch scheduling failed:", error?.message ?? error);
|
|
3425
|
+
});
|
|
3426
|
+
}
|
|
3494
3427
|
return hash;
|
|
3495
3428
|
} catch (e) {
|
|
3496
3429
|
if (hash) {
|
|
3497
3430
|
try {
|
|
3498
|
-
globalThis.peernet.publish("invalid-transaction", hash);
|
|
3431
|
+
await globalThis.peernet.publish("invalid-transaction", hash);
|
|
3499
3432
|
} catch (publishError) {
|
|
3500
3433
|
debug("peernet publish failed: invalid-transaction", publishError?.message ?? publishError);
|
|
3501
3434
|
}
|
|
@@ -3513,7 +3446,7 @@ class Chain extends VersionControl {
|
|
|
3513
3446
|
const event = await super.sendTransaction(transactionMessage);
|
|
3514
3447
|
await this.#sendTransaction(transactionMessage.encoded);
|
|
3515
3448
|
try {
|
|
3516
|
-
globalThis.peernet.publish("send-transaction", transactionMessage.encoded);
|
|
3449
|
+
await globalThis.peernet.publish("send-transaction", transactionMessage.encoded);
|
|
3517
3450
|
} catch (publishError) {
|
|
3518
3451
|
debug("peernet publish failed: send-transaction", publishError?.message ?? publishError);
|
|
3519
3452
|
}
|