@leofcoin/chain 1.7.157 → 1.8.1
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 +19 -80
- package/exports/chain.js +19 -80
- package/package.json +1 -1
package/exports/browser/chain.js
CHANGED
|
@@ -4189,7 +4189,7 @@ class Machine {
|
|
|
4189
4189
|
break;
|
|
4190
4190
|
}
|
|
4191
4191
|
case 'debug': {
|
|
4192
|
-
debug
|
|
4192
|
+
// debug(data.message)
|
|
4193
4193
|
if (data.message.includes('loaded transactions for block:')) {
|
|
4194
4194
|
pubsub.publish('block-loaded', data.message.replace('loaded transactions for block: ', '').split(' @')[0]);
|
|
4195
4195
|
}
|
|
@@ -4576,7 +4576,7 @@ class Machine {
|
|
|
4576
4576
|
}
|
|
4577
4577
|
async addLoadedBlock(block) {
|
|
4578
4578
|
debug$2(`adding loaded block: ${block.index}@${block.hash}`);
|
|
4579
|
-
|
|
4579
|
+
debug$2(JSON.stringify(block, jsonStringifyBigInt));
|
|
4580
4580
|
if (block.decoded)
|
|
4581
4581
|
block = { ...block.decoded, hash: await block.hash() };
|
|
4582
4582
|
return this.#askWorker('addLoadedBlock', JSON.stringify(block, jsonStringifyBigInt));
|
|
@@ -4640,7 +4640,6 @@ class State extends Contract {
|
|
|
4640
4640
|
// Block resolution state
|
|
4641
4641
|
#resolvingBlocks;
|
|
4642
4642
|
#maxConcurrentResolves;
|
|
4643
|
-
#txConcurrency;
|
|
4644
4643
|
#totalSize;
|
|
4645
4644
|
#lastResolved;
|
|
4646
4645
|
#lastResolvedTime;
|
|
@@ -4727,7 +4726,6 @@ class State extends Contract {
|
|
|
4727
4726
|
// Block resolution state
|
|
4728
4727
|
this.#resolvingBlocks = new Set();
|
|
4729
4728
|
this.#maxConcurrentResolves = 10;
|
|
4730
|
-
this.#txConcurrency = 25;
|
|
4731
4729
|
this.knownBlocks = [];
|
|
4732
4730
|
this.#totalSize = 0;
|
|
4733
4731
|
this._wantList = [];
|
|
@@ -4871,9 +4869,16 @@ class State extends Contract {
|
|
|
4871
4869
|
}
|
|
4872
4870
|
// Fetch all missing transactions in parallel
|
|
4873
4871
|
if (transactionsToFetch.length > 0) {
|
|
4874
|
-
const
|
|
4875
|
-
// Batch store all transactions
|
|
4876
|
-
|
|
4872
|
+
const fetchedResults = await Promise.allSettled(transactionsToFetch.map((txHash) => globalThis.peernet.get(txHash, 'transaction')));
|
|
4873
|
+
// Batch store all transactions that were successfully fetched
|
|
4874
|
+
for (let i = 0; i < fetchedResults.length; i++) {
|
|
4875
|
+
if (fetchedResults[i].status === 'fulfilled') {
|
|
4876
|
+
await globalThis.transactionStore.put(transactionsToFetch[i], fetchedResults[i].value);
|
|
4877
|
+
}
|
|
4878
|
+
else {
|
|
4879
|
+
debug$1(`failed to fetch transaction ${transactionsToFetch[i]}: ${fetchedResults[i].reason?.message || fetchedResults[i].reason}`);
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4877
4882
|
}
|
|
4878
4883
|
// Remove from pool
|
|
4879
4884
|
await Promise.all(transactionHashes.map(async (txHash) => {
|
|
@@ -4896,52 +4901,6 @@ class State extends Contract {
|
|
|
4896
4901
|
this.#resolvingBlocks.delete(hash);
|
|
4897
4902
|
}
|
|
4898
4903
|
}
|
|
4899
|
-
// Small utility to keep event loop responsive
|
|
4900
|
-
async #sleep(ms) {
|
|
4901
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4902
|
-
}
|
|
4903
|
-
// Run a list of tasks with bounded concurrency
|
|
4904
|
-
async #runWithConcurrency(items, concurrency, handler) {
|
|
4905
|
-
let index = 0;
|
|
4906
|
-
const total = items.length;
|
|
4907
|
-
const worker = async () => {
|
|
4908
|
-
while (true) {
|
|
4909
|
-
const current = index++;
|
|
4910
|
-
if (current >= total)
|
|
4911
|
-
break;
|
|
4912
|
-
try {
|
|
4913
|
-
await handler(items[current], current);
|
|
4914
|
-
if (current % 50 === 0)
|
|
4915
|
-
debug$1(`executed ${current}/${total}`);
|
|
4916
|
-
}
|
|
4917
|
-
catch (e) {
|
|
4918
|
-
debug$1(`transaction handler error at ${current}: ${e}`);
|
|
4919
|
-
}
|
|
4920
|
-
// yield a tick every few ops to avoid blocking
|
|
4921
|
-
if (current % 25 === 0)
|
|
4922
|
-
await this.#sleep(1);
|
|
4923
|
-
}
|
|
4924
|
-
};
|
|
4925
|
-
const workers = Array.from({ length: Math.min(concurrency, Math.max(1, total)) }, () => worker());
|
|
4926
|
-
await Promise.all(workers);
|
|
4927
|
-
}
|
|
4928
|
-
// Execute a single transaction with a timeout to avoid indefinite hangs
|
|
4929
|
-
async #executeWithTimeout(transaction, timeoutMs) {
|
|
4930
|
-
const timeout = timeoutMs ?? this.resolveTimeout ?? 5000;
|
|
4931
|
-
let timer;
|
|
4932
|
-
try {
|
|
4933
|
-
return await Promise.race([
|
|
4934
|
-
this.#machine.execute(transaction.decoded.to, transaction.decoded.method, transaction.decoded.params),
|
|
4935
|
-
new Promise((_, reject) => {
|
|
4936
|
-
timer = setTimeout(() => reject(new Error('transaction execution timeout')), timeout);
|
|
4937
|
-
})
|
|
4938
|
-
]);
|
|
4939
|
-
}
|
|
4940
|
-
finally {
|
|
4941
|
-
if (timer)
|
|
4942
|
-
clearTimeout(timer);
|
|
4943
|
-
}
|
|
4944
|
-
}
|
|
4945
4904
|
async #buildBlockChain(latestHash, maxBlocks = 1000) {
|
|
4946
4905
|
const chain = [];
|
|
4947
4906
|
let currentHash = latestHash;
|
|
@@ -5137,7 +5096,7 @@ class State extends Contract {
|
|
|
5137
5096
|
// todo throw error
|
|
5138
5097
|
async #_executeTransaction(transaction) {
|
|
5139
5098
|
try {
|
|
5140
|
-
await this.#
|
|
5099
|
+
await this.#machine.execute(transaction.decoded.to, transaction.decoded.method, transaction.decoded.params);
|
|
5141
5100
|
// await globalThis.accountsStore.put(transaction.decoded.from, String(transaction.decoded.nonce))
|
|
5142
5101
|
// if (transaction.decoded.to === nativeToken) {
|
|
5143
5102
|
// this.#nativeCalls += 1
|
|
@@ -5203,8 +5162,7 @@ class State extends Contract {
|
|
|
5203
5162
|
}
|
|
5204
5163
|
transactions = transactions.filter((transaction) => !transaction.decoded.priority);
|
|
5205
5164
|
debug$1(`executing ${transactions.length} transactions for block ${block.index}`);
|
|
5206
|
-
|
|
5207
|
-
await this.#runWithConcurrency(transactions, this.#txConcurrency, async (tx) => this.#_executeTransaction(tx));
|
|
5165
|
+
await Promise.all(transactions.map((transaction) => this.#_executeTransaction(transaction)));
|
|
5208
5166
|
this.#blocks[block.index].loaded = true;
|
|
5209
5167
|
debug$1(`executed transactions for block ${block.index}`);
|
|
5210
5168
|
if (Number(block.index) === 0)
|
|
@@ -5915,8 +5873,9 @@ class Chain extends VersionControl {
|
|
|
5915
5873
|
}
|
|
5916
5874
|
}
|
|
5917
5875
|
async #addBlock(block) {
|
|
5918
|
-
|
|
5919
|
-
const
|
|
5876
|
+
// Store the original received encoded bytes for validation
|
|
5877
|
+
const receivedEncoded = block instanceof BlockMessage ? block.encoded : block;
|
|
5878
|
+
const blockMessage = await new BlockMessage(block);
|
|
5920
5879
|
const hash = await blockMessage.hash();
|
|
5921
5880
|
// Verify data integrity: re-encode should produce the same bytes
|
|
5922
5881
|
const canonicalEncoded = blockMessage.encoded;
|
|
@@ -6156,7 +6115,7 @@ class Chain extends VersionControl {
|
|
|
6156
6115
|
debug(`created block: ${hash} @${block.index}`);
|
|
6157
6116
|
// Publish canonical encoded form via codec interface
|
|
6158
6117
|
console.log(`[chain] 📤 Publishing block #${block.index} | hash: ${hash} | encoded bytes: ${blockMessage.encoded.length}`);
|
|
6159
|
-
globalThis.peernet.publish('add-block',
|
|
6118
|
+
globalThis.peernet.publish('add-block', blockMessage.decoded);
|
|
6160
6119
|
globalThis.pubsub.publish('add-block', blockMessage.decoded);
|
|
6161
6120
|
}
|
|
6162
6121
|
catch (error) {
|
|
@@ -6191,7 +6150,7 @@ class Chain extends VersionControl {
|
|
|
6191
6150
|
const transactionMessage = await new TransactionMessage({ ...transaction });
|
|
6192
6151
|
const event = await super.sendTransaction(transactionMessage);
|
|
6193
6152
|
this.#sendTransaction(transactionMessage.encoded);
|
|
6194
|
-
globalThis.peernet.publish('send-transaction', transactionMessage.
|
|
6153
|
+
globalThis.peernet.publish('send-transaction', transactionMessage.decoded);
|
|
6195
6154
|
return event;
|
|
6196
6155
|
}
|
|
6197
6156
|
async addContract(transaction, contractMessage) {
|
|
@@ -6297,26 +6256,6 @@ class Chain extends VersionControl {
|
|
|
6297
6256
|
console.warn('Failed to reconnect to peers:', error.message);
|
|
6298
6257
|
}
|
|
6299
6258
|
}
|
|
6300
|
-
#normalizeBytes(input) {
|
|
6301
|
-
if (input instanceof Uint8Array)
|
|
6302
|
-
return input;
|
|
6303
|
-
if (Array.isArray(input))
|
|
6304
|
-
return Uint8Array.from(input);
|
|
6305
|
-
if (input && typeof input === 'object') {
|
|
6306
|
-
if (input.type === 'Buffer' && Array.isArray(input.data))
|
|
6307
|
-
return Uint8Array.from(input.data);
|
|
6308
|
-
const values = Object.values(input);
|
|
6309
|
-
if (values.length > 0 && values.every((v) => typeof v === 'number'))
|
|
6310
|
-
return Uint8Array.from(values);
|
|
6311
|
-
}
|
|
6312
|
-
try {
|
|
6313
|
-
// @ts-ignore
|
|
6314
|
-
return new Uint8Array(input);
|
|
6315
|
-
}
|
|
6316
|
-
catch {
|
|
6317
|
-
throw new Error('Unsupported block payload format for normalization');
|
|
6318
|
-
}
|
|
6319
|
-
}
|
|
6320
6259
|
}
|
|
6321
6260
|
|
|
6322
6261
|
export { Chain as default };
|
package/exports/chain.js
CHANGED
|
@@ -330,7 +330,7 @@ class Machine {
|
|
|
330
330
|
break;
|
|
331
331
|
}
|
|
332
332
|
case 'debug': {
|
|
333
|
-
debug
|
|
333
|
+
// debug(data.message)
|
|
334
334
|
if (data.message.includes('loaded transactions for block:')) {
|
|
335
335
|
pubsub.publish('block-loaded', data.message.replace('loaded transactions for block: ', '').split(' @')[0]);
|
|
336
336
|
}
|
|
@@ -717,7 +717,7 @@ class Machine {
|
|
|
717
717
|
}
|
|
718
718
|
async addLoadedBlock(block) {
|
|
719
719
|
debug$2(`adding loaded block: ${block.index}@${block.hash}`);
|
|
720
|
-
|
|
720
|
+
debug$2(JSON.stringify(block, jsonStringifyBigInt));
|
|
721
721
|
if (block.decoded)
|
|
722
722
|
block = { ...block.decoded, hash: await block.hash() };
|
|
723
723
|
return this.#askWorker('addLoadedBlock', JSON.stringify(block, jsonStringifyBigInt));
|
|
@@ -781,7 +781,6 @@ class State extends Contract {
|
|
|
781
781
|
// Block resolution state
|
|
782
782
|
#resolvingBlocks;
|
|
783
783
|
#maxConcurrentResolves;
|
|
784
|
-
#txConcurrency;
|
|
785
784
|
#totalSize;
|
|
786
785
|
#lastResolved;
|
|
787
786
|
#lastResolvedTime;
|
|
@@ -868,7 +867,6 @@ class State extends Contract {
|
|
|
868
867
|
// Block resolution state
|
|
869
868
|
this.#resolvingBlocks = new Set();
|
|
870
869
|
this.#maxConcurrentResolves = 10;
|
|
871
|
-
this.#txConcurrency = 25;
|
|
872
870
|
this.knownBlocks = [];
|
|
873
871
|
this.#totalSize = 0;
|
|
874
872
|
this._wantList = [];
|
|
@@ -1012,9 +1010,16 @@ class State extends Contract {
|
|
|
1012
1010
|
}
|
|
1013
1011
|
// Fetch all missing transactions in parallel
|
|
1014
1012
|
if (transactionsToFetch.length > 0) {
|
|
1015
|
-
const
|
|
1016
|
-
// Batch store all transactions
|
|
1017
|
-
|
|
1013
|
+
const fetchedResults = await Promise.allSettled(transactionsToFetch.map((txHash) => globalThis.peernet.get(txHash, 'transaction')));
|
|
1014
|
+
// Batch store all transactions that were successfully fetched
|
|
1015
|
+
for (let i = 0; i < fetchedResults.length; i++) {
|
|
1016
|
+
if (fetchedResults[i].status === 'fulfilled') {
|
|
1017
|
+
await globalThis.transactionStore.put(transactionsToFetch[i], fetchedResults[i].value);
|
|
1018
|
+
}
|
|
1019
|
+
else {
|
|
1020
|
+
debug$1(`failed to fetch transaction ${transactionsToFetch[i]}: ${fetchedResults[i].reason?.message || fetchedResults[i].reason}`);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1018
1023
|
}
|
|
1019
1024
|
// Remove from pool
|
|
1020
1025
|
await Promise.all(transactionHashes.map(async (txHash) => {
|
|
@@ -1037,52 +1042,6 @@ class State extends Contract {
|
|
|
1037
1042
|
this.#resolvingBlocks.delete(hash);
|
|
1038
1043
|
}
|
|
1039
1044
|
}
|
|
1040
|
-
// Small utility to keep event loop responsive
|
|
1041
|
-
async #sleep(ms) {
|
|
1042
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1043
|
-
}
|
|
1044
|
-
// Run a list of tasks with bounded concurrency
|
|
1045
|
-
async #runWithConcurrency(items, concurrency, handler) {
|
|
1046
|
-
let index = 0;
|
|
1047
|
-
const total = items.length;
|
|
1048
|
-
const worker = async () => {
|
|
1049
|
-
while (true) {
|
|
1050
|
-
const current = index++;
|
|
1051
|
-
if (current >= total)
|
|
1052
|
-
break;
|
|
1053
|
-
try {
|
|
1054
|
-
await handler(items[current], current);
|
|
1055
|
-
if (current % 50 === 0)
|
|
1056
|
-
debug$1(`executed ${current}/${total}`);
|
|
1057
|
-
}
|
|
1058
|
-
catch (e) {
|
|
1059
|
-
debug$1(`transaction handler error at ${current}: ${e}`);
|
|
1060
|
-
}
|
|
1061
|
-
// yield a tick every few ops to avoid blocking
|
|
1062
|
-
if (current % 25 === 0)
|
|
1063
|
-
await this.#sleep(1);
|
|
1064
|
-
}
|
|
1065
|
-
};
|
|
1066
|
-
const workers = Array.from({ length: Math.min(concurrency, Math.max(1, total)) }, () => worker());
|
|
1067
|
-
await Promise.all(workers);
|
|
1068
|
-
}
|
|
1069
|
-
// Execute a single transaction with a timeout to avoid indefinite hangs
|
|
1070
|
-
async #executeWithTimeout(transaction, timeoutMs) {
|
|
1071
|
-
const timeout = timeoutMs ?? this.resolveTimeout ?? 5000;
|
|
1072
|
-
let timer;
|
|
1073
|
-
try {
|
|
1074
|
-
return await Promise.race([
|
|
1075
|
-
this.#machine.execute(transaction.decoded.to, transaction.decoded.method, transaction.decoded.params),
|
|
1076
|
-
new Promise((_, reject) => {
|
|
1077
|
-
timer = setTimeout(() => reject(new Error('transaction execution timeout')), timeout);
|
|
1078
|
-
})
|
|
1079
|
-
]);
|
|
1080
|
-
}
|
|
1081
|
-
finally {
|
|
1082
|
-
if (timer)
|
|
1083
|
-
clearTimeout(timer);
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
1045
|
async #buildBlockChain(latestHash, maxBlocks = 1000) {
|
|
1087
1046
|
const chain = [];
|
|
1088
1047
|
let currentHash = latestHash;
|
|
@@ -1278,7 +1237,7 @@ class State extends Contract {
|
|
|
1278
1237
|
// todo throw error
|
|
1279
1238
|
async #_executeTransaction(transaction) {
|
|
1280
1239
|
try {
|
|
1281
|
-
await this.#
|
|
1240
|
+
await this.#machine.execute(transaction.decoded.to, transaction.decoded.method, transaction.decoded.params);
|
|
1282
1241
|
// await globalThis.accountsStore.put(transaction.decoded.from, String(transaction.decoded.nonce))
|
|
1283
1242
|
// if (transaction.decoded.to === nativeToken) {
|
|
1284
1243
|
// this.#nativeCalls += 1
|
|
@@ -1344,8 +1303,7 @@ class State extends Contract {
|
|
|
1344
1303
|
}
|
|
1345
1304
|
transactions = transactions.filter((transaction) => !transaction.decoded.priority);
|
|
1346
1305
|
debug$1(`executing ${transactions.length} transactions for block ${block.index}`);
|
|
1347
|
-
|
|
1348
|
-
await this.#runWithConcurrency(transactions, this.#txConcurrency, async (tx) => this.#_executeTransaction(tx));
|
|
1306
|
+
await Promise.all(transactions.map((transaction) => this.#_executeTransaction(transaction)));
|
|
1349
1307
|
this.#blocks[block.index].loaded = true;
|
|
1350
1308
|
debug$1(`executed transactions for block ${block.index}`);
|
|
1351
1309
|
if (Number(block.index) === 0)
|
|
@@ -2056,8 +2014,9 @@ class Chain extends VersionControl {
|
|
|
2056
2014
|
}
|
|
2057
2015
|
}
|
|
2058
2016
|
async #addBlock(block) {
|
|
2059
|
-
|
|
2060
|
-
const
|
|
2017
|
+
// Store the original received encoded bytes for validation
|
|
2018
|
+
const receivedEncoded = block instanceof BlockMessage ? block.encoded : block;
|
|
2019
|
+
const blockMessage = await new BlockMessage(block);
|
|
2061
2020
|
const hash = await blockMessage.hash();
|
|
2062
2021
|
// Verify data integrity: re-encode should produce the same bytes
|
|
2063
2022
|
const canonicalEncoded = blockMessage.encoded;
|
|
@@ -2297,7 +2256,7 @@ class Chain extends VersionControl {
|
|
|
2297
2256
|
debug(`created block: ${hash} @${block.index}`);
|
|
2298
2257
|
// Publish canonical encoded form via codec interface
|
|
2299
2258
|
console.log(`[chain] 📤 Publishing block #${block.index} | hash: ${hash} | encoded bytes: ${blockMessage.encoded.length}`);
|
|
2300
|
-
globalThis.peernet.publish('add-block',
|
|
2259
|
+
globalThis.peernet.publish('add-block', blockMessage.decoded);
|
|
2301
2260
|
globalThis.pubsub.publish('add-block', blockMessage.decoded);
|
|
2302
2261
|
}
|
|
2303
2262
|
catch (error) {
|
|
@@ -2332,7 +2291,7 @@ class Chain extends VersionControl {
|
|
|
2332
2291
|
const transactionMessage = await new TransactionMessage({ ...transaction });
|
|
2333
2292
|
const event = await super.sendTransaction(transactionMessage);
|
|
2334
2293
|
this.#sendTransaction(transactionMessage.encoded);
|
|
2335
|
-
globalThis.peernet.publish('send-transaction', transactionMessage.
|
|
2294
|
+
globalThis.peernet.publish('send-transaction', transactionMessage.decoded);
|
|
2336
2295
|
return event;
|
|
2337
2296
|
}
|
|
2338
2297
|
async addContract(transaction, contractMessage) {
|
|
@@ -2438,26 +2397,6 @@ class Chain extends VersionControl {
|
|
|
2438
2397
|
console.warn('Failed to reconnect to peers:', error.message);
|
|
2439
2398
|
}
|
|
2440
2399
|
}
|
|
2441
|
-
#normalizeBytes(input) {
|
|
2442
|
-
if (input instanceof Uint8Array)
|
|
2443
|
-
return input;
|
|
2444
|
-
if (Array.isArray(input))
|
|
2445
|
-
return Uint8Array.from(input);
|
|
2446
|
-
if (input && typeof input === 'object') {
|
|
2447
|
-
if (input.type === 'Buffer' && Array.isArray(input.data))
|
|
2448
|
-
return Uint8Array.from(input.data);
|
|
2449
|
-
const values = Object.values(input);
|
|
2450
|
-
if (values.length > 0 && values.every((v) => typeof v === 'number'))
|
|
2451
|
-
return Uint8Array.from(values);
|
|
2452
|
-
}
|
|
2453
|
-
try {
|
|
2454
|
-
// @ts-ignore
|
|
2455
|
-
return new Uint8Array(input);
|
|
2456
|
-
}
|
|
2457
|
-
catch {
|
|
2458
|
-
throw new Error('Unsupported block payload format for normalization');
|
|
2459
|
-
}
|
|
2460
|
-
}
|
|
2461
2400
|
}
|
|
2462
2401
|
|
|
2463
2402
|
export { Chain as default };
|