@leofcoin/chain 1.10.6 → 1.10.8
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/{browser-D-r0O9Qn-8WfVE0Ux.js → browser-D-r0O9Qn-BZDYY6cg.js} +2 -2
- package/exports/browser/{browser-_hiyXwPp-DAxbV-UB.js → browser-_hiyXwPp-DYI1tyUr.js} +2 -2
- package/exports/browser/chain.js +185 -140
- package/exports/browser/{client-BVhUamQG-z0FD6cVJ.js → client-BVhUamQG-D-D1e_x8.js} +4 -4
- package/exports/browser/{constants-CVkCJ-VS.js → constants-gMYZLHKp.js} +1 -1
- package/exports/browser/{index-BD0Anx7_-Dgedz8qH.js → index-BD0Anx7_-Dg4_tCeN.js} +2 -2
- package/exports/browser/{messages-UKnuelZ7-CjCqR-Qe.js → messages-UKnuelZ7-DJT-98q-.js} +2 -2
- package/exports/browser/{node-browser-sxrQkd7t.js → node-browser-DlzZ5CP_.js} +4 -4
- package/exports/browser/node-browser.js +2 -2
- package/exports/browser/workers/machine-worker.js +8 -8
- package/exports/chain.js +175 -130
- package/exports/workers/machine-worker.js +8 -8
- package/package.json +1 -1
package/exports/chain.js
CHANGED
|
@@ -1115,6 +1115,87 @@ class Jobber {
|
|
|
1115
1115
|
}
|
|
1116
1116
|
}
|
|
1117
1117
|
|
|
1118
|
+
const MAX_RESPONSE_DEPTH$1 = 3;
|
|
1119
|
+
const asLastBlockMessage = async (blockInput, claimedHash) => {
|
|
1120
|
+
const block = new BlockMessage(blockInput);
|
|
1121
|
+
const hash = await block.hash();
|
|
1122
|
+
if (claimedHash && hash !== claimedHash) {
|
|
1123
|
+
throw new Error(`lastBlock hash mismatch: expected ${claimedHash}, got ${hash}`);
|
|
1124
|
+
}
|
|
1125
|
+
return new LastBlockMessage({ hash, index: block.decoded.index });
|
|
1126
|
+
};
|
|
1127
|
+
const resolveLegacyHash = async (hash) => {
|
|
1128
|
+
const blockData = await globalThis.peernet?.get?.(hash, "block");
|
|
1129
|
+
if (!blockData) throw new Error(`unable to resolve lastBlock hash: ${hash}`);
|
|
1130
|
+
return asLastBlockMessage(blockData, hash);
|
|
1131
|
+
};
|
|
1132
|
+
const resolveLastBlockMessage = async (result, depth = 0) => {
|
|
1133
|
+
if (depth > MAX_RESPONSE_DEPTH$1) throw new Error("lastBlock response nesting exceeds limit");
|
|
1134
|
+
if (result instanceof Uint8Array) {
|
|
1135
|
+
let codec;
|
|
1136
|
+
try {
|
|
1137
|
+
codec = new Codec(result);
|
|
1138
|
+
} catch {
|
|
1139
|
+
}
|
|
1140
|
+
if (codec) {
|
|
1141
|
+
if (codec.name === "peernet-response") {
|
|
1142
|
+
const ResponseMessage = globalThis.peernet?.protos?.["peernet-response"];
|
|
1143
|
+
if (!ResponseMessage) throw new Error("peernet-response codec is not registered");
|
|
1144
|
+
const wrapped = new ResponseMessage(result);
|
|
1145
|
+
if (wrapped?.decoded?.response === void 0) throw new Error("peernet-response has no response payload");
|
|
1146
|
+
return resolveLastBlockMessage(wrapped.decoded.response, depth + 1);
|
|
1147
|
+
}
|
|
1148
|
+
if (codec.name === "last-block-message") return new LastBlockMessage(result);
|
|
1149
|
+
if (codec.name === "block-message") return asLastBlockMessage(result);
|
|
1150
|
+
}
|
|
1151
|
+
const candidate = new TextDecoder().decode(result);
|
|
1152
|
+
if (candidate) return resolveLegacyHash(candidate);
|
|
1153
|
+
}
|
|
1154
|
+
if (typeof result === "string") return resolveLegacyHash(result);
|
|
1155
|
+
if (result && typeof result === "object") {
|
|
1156
|
+
const response = result.decoded?.response ?? result.response;
|
|
1157
|
+
if (response !== void 0) return resolveLastBlockMessage(response, depth + 1);
|
|
1158
|
+
if ("hash" in result && "index" in result) return new LastBlockMessage(result);
|
|
1159
|
+
if ("previousHash" in result && "index" in result) return asLastBlockMessage(result);
|
|
1160
|
+
}
|
|
1161
|
+
throw new Error(`invalid lastBlock payload: ${typeof result}`);
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1164
|
+
const MAX_RESPONSE_DEPTH = 3;
|
|
1165
|
+
const decodeResponsePayload = async (result, depth = 0) => {
|
|
1166
|
+
if (depth > MAX_RESPONSE_DEPTH) throw new Error("peernet response nesting exceeds limit");
|
|
1167
|
+
if (result instanceof Uint8Array) {
|
|
1168
|
+
let codec;
|
|
1169
|
+
try {
|
|
1170
|
+
codec = new Codec(result);
|
|
1171
|
+
} catch {
|
|
1172
|
+
}
|
|
1173
|
+
if (codec?.name === "peernet-response") {
|
|
1174
|
+
const ResponseMessage = globalThis.peernet?.protos?.["peernet-response"];
|
|
1175
|
+
if (!ResponseMessage) throw new Error("peernet-response codec is not registered");
|
|
1176
|
+
const wrapped = new ResponseMessage(result);
|
|
1177
|
+
return decodeResponsePayload(wrapped.decoded.response, depth + 1);
|
|
1178
|
+
}
|
|
1179
|
+
try {
|
|
1180
|
+
return JSON.parse(new TextDecoder().decode(result));
|
|
1181
|
+
} catch {
|
|
1182
|
+
return result;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
if (result && typeof result === "object") {
|
|
1186
|
+
const response = result.decoded?.response ?? result.response;
|
|
1187
|
+
if (response !== void 0) return decodeResponsePayload(response, depth + 1);
|
|
1188
|
+
}
|
|
1189
|
+
if (typeof result === "string") {
|
|
1190
|
+
try {
|
|
1191
|
+
return JSON.parse(result);
|
|
1192
|
+
} catch {
|
|
1193
|
+
return result;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return result;
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1118
1199
|
const debug$1 = createDebugger("leofcoin/state");
|
|
1119
1200
|
class State extends Contract {
|
|
1120
1201
|
constructor(config) {
|
|
@@ -1194,42 +1275,6 @@ class State extends Contract {
|
|
|
1194
1275
|
get resolving() {
|
|
1195
1276
|
return this.#resolving;
|
|
1196
1277
|
}
|
|
1197
|
-
async #resolveLastBlockMessage(result) {
|
|
1198
|
-
if (result instanceof Uint8Array) {
|
|
1199
|
-
try {
|
|
1200
|
-
let payload = result;
|
|
1201
|
-
for (let i = 0; i < 3; i += 1) {
|
|
1202
|
-
try {
|
|
1203
|
-
const wrapped = await new globalThis.peernet.protos["peernet-response"](payload);
|
|
1204
|
-
if (wrapped?.decoded?.response === void 0) break;
|
|
1205
|
-
payload = wrapped.decoded.response;
|
|
1206
|
-
} catch {
|
|
1207
|
-
break;
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
if (payload !== result) return this.#resolveLastBlockMessage(payload);
|
|
1211
|
-
return new LastBlockMessage(result);
|
|
1212
|
-
} catch {
|
|
1213
|
-
const candidate = new TextDecoder().decode(result);
|
|
1214
|
-
if (candidate) {
|
|
1215
|
-
const blockData = await globalThis.peernet.get(candidate, "block");
|
|
1216
|
-
if (blockData) return new BlockMessage(blockData);
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
if (typeof result === "string") {
|
|
1221
|
-
const blockData = await globalThis.peernet.get(result, "block");
|
|
1222
|
-
if (blockData) return new BlockMessage(blockData);
|
|
1223
|
-
}
|
|
1224
|
-
if (result && typeof result === "object") {
|
|
1225
|
-
const response = result.decoded?.response ?? result.response;
|
|
1226
|
-
if (response !== void 0) return this.#resolveLastBlockMessage(response);
|
|
1227
|
-
if ("hash" in result && "index" in result) {
|
|
1228
|
-
return new LastBlockMessage(result);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
throw new Error(`invalid lastBlock payload: ${typeof result}`);
|
|
1232
|
-
}
|
|
1233
1278
|
get contracts() {
|
|
1234
1279
|
return this.#machine.contracts;
|
|
1235
1280
|
}
|
|
@@ -1674,21 +1719,9 @@ class State extends Contract {
|
|
|
1674
1719
|
compatiblePeerCount += 1;
|
|
1675
1720
|
const task = async () => {
|
|
1676
1721
|
try {
|
|
1677
|
-
|
|
1722
|
+
const result = await peer.request(node.encoded);
|
|
1678
1723
|
const resultType = result instanceof Uint8Array ? `bytes:${result.length}` : typeof result;
|
|
1679
1724
|
debug$1(`lastBlock result type: ${resultType}`);
|
|
1680
|
-
console.log({ result });
|
|
1681
|
-
if (result instanceof Uint8Array) {
|
|
1682
|
-
for (let i = 0; i < 3; i += 1) {
|
|
1683
|
-
try {
|
|
1684
|
-
const wrapped = await new globalThis.peernet.protos["peernet-response"](result);
|
|
1685
|
-
if (wrapped?.decoded?.response === void 0) break;
|
|
1686
|
-
result = wrapped.decoded.response;
|
|
1687
|
-
} catch {
|
|
1688
|
-
break;
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
1725
|
return { result, peer };
|
|
1693
1726
|
} catch (error) {
|
|
1694
1727
|
const peerId = peer?.peerId || peer?.id || peer?.address || "unknown";
|
|
@@ -1712,7 +1745,7 @@ class State extends Contract {
|
|
|
1712
1745
|
console.log({ promises });
|
|
1713
1746
|
promises = await Promise.all(
|
|
1714
1747
|
promises.map(async (item) => ({
|
|
1715
|
-
value: (await
|
|
1748
|
+
value: (await resolveLastBlockMessage(item.value)).decoded,
|
|
1716
1749
|
peer: item.peer
|
|
1717
1750
|
}))
|
|
1718
1751
|
);
|
|
@@ -1733,10 +1766,11 @@ class State extends Contract {
|
|
|
1733
1766
|
});
|
|
1734
1767
|
let node2 = await globalThis.peernet.prepareMessage(data2);
|
|
1735
1768
|
try {
|
|
1736
|
-
|
|
1737
|
-
|
|
1769
|
+
const message2 = await decodeResponsePayload(await peer.request(node2.encoded));
|
|
1770
|
+
const blocks = message2?.blocks;
|
|
1771
|
+
if (!Array.isArray(blocks)) throw new Error("knownBlocks response does not contain a blocks array");
|
|
1738
1772
|
const MAX_WANTLIST_SIZE = 1e3;
|
|
1739
|
-
const incoming =
|
|
1773
|
+
const incoming = blocks.filter((block) => !this.knownBlocks.includes(block));
|
|
1740
1774
|
const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
|
|
1741
1775
|
if (remaining > 0) this.wantList.push(...incoming.slice(0, remaining));
|
|
1742
1776
|
} catch (error) {
|
|
@@ -1816,28 +1850,20 @@ class State extends Contract {
|
|
|
1816
1850
|
this.#chainState = "loaded";
|
|
1817
1851
|
return true;
|
|
1818
1852
|
}
|
|
1819
|
-
promiseRequests(promises) {
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
return { value: node.decoded.response, peer: value.peer };
|
|
1834
|
-
});
|
|
1835
|
-
promises = await Promise.all(promises);
|
|
1836
|
-
resolve(promises);
|
|
1837
|
-
} else {
|
|
1838
|
-
resolve([]);
|
|
1839
|
-
}
|
|
1840
|
-
});
|
|
1853
|
+
async promiseRequests(promises) {
|
|
1854
|
+
let timeout;
|
|
1855
|
+
const settled = await Promise.race([
|
|
1856
|
+
Promise.allSettled(promises),
|
|
1857
|
+
new Promise((resolve) => {
|
|
1858
|
+
timeout = setTimeout(() => resolve(null), this.requestTimeout);
|
|
1859
|
+
})
|
|
1860
|
+
]);
|
|
1861
|
+
clearTimeout(timeout);
|
|
1862
|
+
if (settled === null) {
|
|
1863
|
+
debug$1("sync timed out");
|
|
1864
|
+
return [];
|
|
1865
|
+
}
|
|
1866
|
+
return settled.filter(({ status }) => status === "fulfilled").map(({ value }) => ({ value: value.result, peer: value.peer }));
|
|
1841
1867
|
}
|
|
1842
1868
|
get canSync() {
|
|
1843
1869
|
if (this.#chainSyncing) return false;
|
|
@@ -2250,6 +2276,46 @@ const validateChainLink = (localTip, incoming) => {
|
|
|
2250
2276
|
return "append";
|
|
2251
2277
|
};
|
|
2252
2278
|
|
|
2279
|
+
const BLOCK_REWARD = 150n;
|
|
2280
|
+
const validateCanonicalValidatorSet = (blockIndex, expectedValidators, validators) => {
|
|
2281
|
+
const actualValidators = validators.map(({ address }) => address);
|
|
2282
|
+
const canonicalExpected = [...new Set(expectedValidators)].sort();
|
|
2283
|
+
if (actualValidators.length !== canonicalExpected.length || actualValidators.some((address, index) => address !== canonicalExpected[index])) {
|
|
2284
|
+
throw new Error(
|
|
2285
|
+
`Block ${blockIndex} validator set mismatch: expected ${canonicalExpected.join(",")}, got ${actualValidators.join(",")}`
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
};
|
|
2289
|
+
const validateBlockEconomics = (block, calculatedFees) => {
|
|
2290
|
+
if (block.validators.length === 0) {
|
|
2291
|
+
throw new Error(`Block ${block.index} cannot distribute rewards without validators`);
|
|
2292
|
+
}
|
|
2293
|
+
if (block.reward !== BLOCK_REWARD) {
|
|
2294
|
+
throw new Error(`Block ${block.index} has invalid base reward: expected ${BLOCK_REWARD}, got ${block.reward}`);
|
|
2295
|
+
}
|
|
2296
|
+
if (block.fees !== calculatedFees) {
|
|
2297
|
+
throw new Error(`Block ${block.index} has invalid fees: expected ${calculatedFees}, got ${block.fees}`);
|
|
2298
|
+
}
|
|
2299
|
+
const validatorCount = BigInt(block.validators.length);
|
|
2300
|
+
const expectedReward = calculatedFees / validatorCount + BLOCK_REWARD / validatorCount;
|
|
2301
|
+
for (const validator of block.validators) {
|
|
2302
|
+
if (validator.reward !== expectedReward) {
|
|
2303
|
+
throw new Error(
|
|
2304
|
+
`Block ${block.index} has an invalid reward for validator ${validator.address}: expected ${expectedReward}, got ${validator.reward}`
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
|
|
2310
|
+
const resolveTransactionReference = async (expectedHash, transactionData) => {
|
|
2311
|
+
const transaction = transactionData instanceof TransactionMessage ? transactionData : new TransactionMessage(transactionData);
|
|
2312
|
+
const actualHash = await transaction.hash();
|
|
2313
|
+
if (actualHash !== expectedHash) {
|
|
2314
|
+
throw new Error(`Transaction hash mismatch: expected ${expectedHash}, got ${actualHash}`);
|
|
2315
|
+
}
|
|
2316
|
+
return transaction;
|
|
2317
|
+
};
|
|
2318
|
+
|
|
2253
2319
|
const consensusSignableData = (validatorsAddress, type, message) => ({
|
|
2254
2320
|
from: String(message.from),
|
|
2255
2321
|
to: validatorsAddress,
|
|
@@ -2417,8 +2483,23 @@ class Chain extends VersionControl {
|
|
|
2417
2483
|
debug(`[consensus] Block hash mismatch in proposal: expected ${blockHash}, got ${actualHash}`);
|
|
2418
2484
|
return;
|
|
2419
2485
|
}
|
|
2486
|
+
if (BigInt(blockMessage.decoded.index) !== index) {
|
|
2487
|
+
debug(`[consensus] Proposal height ${index} does not match block height ${blockMessage.decoded.index}`);
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2490
|
+
if (blockMessage.decoded.producer !== from) {
|
|
2491
|
+
debug(`[consensus] Proposal sender ${from} does not match block producer ${blockMessage.decoded.producer}`);
|
|
2492
|
+
return;
|
|
2493
|
+
}
|
|
2494
|
+
validateChainLink(localBlock, {
|
|
2495
|
+
index: Number(blockMessage.decoded.index),
|
|
2496
|
+
hash: actualHash,
|
|
2497
|
+
previousHash: String(blockMessage.decoded.previousHash)
|
|
2498
|
+
});
|
|
2499
|
+
await this.#validateBlockValidators(blockMessage);
|
|
2500
|
+
await this.#resolveBlockTransactions(blockMessage);
|
|
2420
2501
|
} catch (e) {
|
|
2421
|
-
debug(`[consensus]
|
|
2502
|
+
debug(`[consensus] Invalid proposed block ${blockHash}:`, e?.message);
|
|
2422
2503
|
return;
|
|
2423
2504
|
}
|
|
2424
2505
|
this.#consensusRound = Number(round);
|
|
@@ -2673,15 +2754,21 @@ class Chain extends VersionControl {
|
|
|
2673
2754
|
if (new Set(validatorAddresses).size !== validatorAddresses.length) {
|
|
2674
2755
|
throw new Error(`Block ${blockMessage.decoded.index} validators contain duplicates`);
|
|
2675
2756
|
}
|
|
2676
|
-
const
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
);
|
|
2683
|
-
|
|
2684
|
-
|
|
2757
|
+
const expectedValidators = await this.staticCall(addresses.validators, "validators");
|
|
2758
|
+
validateCanonicalValidatorSet(blockMessage.decoded.index, expectedValidators, validators);
|
|
2759
|
+
}
|
|
2760
|
+
async #resolveBlockTransactions(blockMessage) {
|
|
2761
|
+
const transactions = await Promise.all(
|
|
2762
|
+
blockMessage.decoded.transactions.map(async (expectedHash) => {
|
|
2763
|
+
const data = await globalThis.peernet.get(expectedHash, "transaction");
|
|
2764
|
+
const transaction = await resolveTransactionReference(expectedHash, data);
|
|
2765
|
+
await this.validateTransactionSignature(transaction);
|
|
2766
|
+
return transaction;
|
|
2767
|
+
})
|
|
2768
|
+
);
|
|
2769
|
+
const calculatedFees = (await Promise.all(transactions.map((transaction) => calculateFee(transaction.decoded)))).reduce((total, fee) => total + BigInt(fee), 0n);
|
|
2770
|
+
validateBlockEconomics(blockMessage.decoded, calculatedFees);
|
|
2771
|
+
return transactions;
|
|
2685
2772
|
}
|
|
2686
2773
|
/** Check if the next block will cross an epoch boundary (block-based timing) */
|
|
2687
2774
|
#isEpochBoundary(blockHeight) {
|
|
@@ -2905,42 +2992,6 @@ class Chain extends VersionControl {
|
|
|
2905
2992
|
throw error;
|
|
2906
2993
|
}
|
|
2907
2994
|
}
|
|
2908
|
-
async #resolveLastBlockMessage(result) {
|
|
2909
|
-
if (result instanceof Uint8Array) {
|
|
2910
|
-
try {
|
|
2911
|
-
let payload = result;
|
|
2912
|
-
for (let i = 0; i < 3; i += 1) {
|
|
2913
|
-
try {
|
|
2914
|
-
const wrapped = await new globalThis.peernet.protos["peernet-response"](payload);
|
|
2915
|
-
if (wrapped?.decoded?.response === void 0) break;
|
|
2916
|
-
payload = wrapped.decoded.response;
|
|
2917
|
-
} catch {
|
|
2918
|
-
break;
|
|
2919
|
-
}
|
|
2920
|
-
}
|
|
2921
|
-
if (payload !== result) return this.#resolveLastBlockMessage(payload);
|
|
2922
|
-
return new LastBlockMessage(result);
|
|
2923
|
-
} catch {
|
|
2924
|
-
const candidate = new TextDecoder().decode(result);
|
|
2925
|
-
if (candidate) {
|
|
2926
|
-
const blockData = await globalThis.peernet.get(candidate, "block");
|
|
2927
|
-
if (blockData) return new BlockMessage(blockData);
|
|
2928
|
-
}
|
|
2929
|
-
}
|
|
2930
|
-
}
|
|
2931
|
-
if (typeof result === "string") {
|
|
2932
|
-
const blockData = await globalThis.peernet.get(result, "block");
|
|
2933
|
-
if (blockData) return new BlockMessage(blockData);
|
|
2934
|
-
}
|
|
2935
|
-
if (result && typeof result === "object") {
|
|
2936
|
-
const response = result.decoded?.response ?? result.response;
|
|
2937
|
-
if (response !== void 0) return this.#resolveLastBlockMessage(response);
|
|
2938
|
-
if ("hash" in result && "index" in result) {
|
|
2939
|
-
return new LastBlockMessage(result);
|
|
2940
|
-
}
|
|
2941
|
-
}
|
|
2942
|
-
throw new Error(`invalid lastBlock payload: ${typeof result}`);
|
|
2943
|
-
}
|
|
2944
2995
|
async #decodeKnownBlocksResponse(response) {
|
|
2945
2996
|
if (!response) return null;
|
|
2946
2997
|
if (Array.isArray(response)) {
|
|
@@ -3073,7 +3124,7 @@ class Chain extends VersionControl {
|
|
|
3073
3124
|
if (lastBlockRaw === void 0 || lastBlockRaw === null) {
|
|
3074
3125
|
throw new Error(`invalid lastBlock payload: ${typeof lastBlockRaw}`);
|
|
3075
3126
|
}
|
|
3076
|
-
const lastBlockMessage = await
|
|
3127
|
+
const lastBlockMessage = await resolveLastBlockMessage(lastBlockRaw);
|
|
3077
3128
|
console.log(lastBlockMessage);
|
|
3078
3129
|
lastBlock = lastBlockMessage.decoded;
|
|
3079
3130
|
} catch (error) {
|
|
@@ -3216,13 +3267,7 @@ class Chain extends VersionControl {
|
|
|
3216
3267
|
}
|
|
3217
3268
|
console.log(`[chain] \u2705 Block data integrity verified: ${hash}`);
|
|
3218
3269
|
await this.#validateBlockValidators(blockMessage);
|
|
3219
|
-
const transactions = await
|
|
3220
|
-
blockMessage.decoded.transactions.map(async (hash2) => {
|
|
3221
|
-
const data = await peernet.get(hash2, "transaction");
|
|
3222
|
-
return new TransactionMessage(data);
|
|
3223
|
-
})
|
|
3224
|
-
);
|
|
3225
|
-
await Promise.all(transactions.map((transaction) => this.validateTransactionSignature(transaction)));
|
|
3270
|
+
const transactions = await this.#resolveBlockTransactions(blockMessage);
|
|
3226
3271
|
await Promise.all(
|
|
3227
3272
|
blockMessage.decoded.transactions.map(async (transactionHash) => {
|
|
3228
3273
|
if (await transactionPoolStore.has(transactionHash)) await transactionPoolStore.delete(transactionHash);
|
|
@@ -3348,7 +3393,7 @@ class Chain extends VersionControl {
|
|
|
3348
3393
|
fees: BigInt(0),
|
|
3349
3394
|
timestamp,
|
|
3350
3395
|
previousHash: "",
|
|
3351
|
-
reward:
|
|
3396
|
+
reward: BLOCK_REWARD,
|
|
3352
3397
|
index: 0,
|
|
3353
3398
|
producer: "",
|
|
3354
3399
|
producerProof: "",
|