@leofcoin/chain 1.9.2 → 1.9.4
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 +111 -89
- package/exports/browser/{constants-BTdMMS4w.js → constants-D_XqG46B.js} +316 -214
- package/exports/browser/node-browser.js +1 -18
- package/exports/browser/workers/block-worker.js +1 -1
- package/exports/browser/workers/machine-worker.js +1 -1
- package/exports/browser/workers/{worker-BrtyXRJ7-BrtyXRJ7.js → worker-Bsi6vKgF-Bsi6vKgF.js} +238 -198
- package/exports/chain.d.ts +0 -1
- package/exports/chain.js +110 -89
- package/exports/workers/block-worker.js +1 -1
- package/exports/workers/machine-worker.js +1 -1
- package/exports/workers/{worker-BrtyXRJ7-BrtyXRJ7.js → worker-Bsi6vKgF-Bsi6vKgF.js} +238 -198
- package/package.json +9 -9
package/exports/browser/chain.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as toBase58, T as TransactionMessage, C as ContractMessage, R as RawTransactionMessage, B as BlockMessage,
|
|
1
|
+
import { t as toBase58, T as TransactionMessage, C as ContractMessage, R as RawTransactionMessage, B as BlockMessage, L as LastBlockMessage, P as PROTOCOL_VERSION, a as REACHED_ONE_ZERO_ZERO, b as PrevoteMessage, c as PrecommitMessage, d as ProposalMessage, e as BWMessage, S as StateMessage, f as BWRequestMessage } from './constants-D_XqG46B.js';
|
|
2
2
|
import { log } from 'console';
|
|
3
3
|
import { log as log$1 } from 'node:console';
|
|
4
4
|
|
|
@@ -3912,11 +3912,25 @@ class Transaction extends Protocol {
|
|
|
3912
3912
|
return Number(nonce);
|
|
3913
3913
|
}
|
|
3914
3914
|
async validateNonce(address, nonce) {
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3915
|
+
// Compare only against the COMMITTED nonce (accountsStore), not the pool max.
|
|
3916
|
+
// The pool may hold many future nonces from batch sends — rejecting lower nonces
|
|
3917
|
+
// because a higher one is already queued would break concurrent batch submission.
|
|
3918
|
+
let committedNonce;
|
|
3919
|
+
try {
|
|
3920
|
+
if (await globalThis.accountsStore.has(address)) {
|
|
3921
|
+
const raw = await globalThis.accountsStore.get(address);
|
|
3922
|
+
committedNonce = Number(new TextDecoder().decode(raw));
|
|
3923
|
+
}
|
|
3924
|
+
else {
|
|
3925
|
+
committedNonce = await this.#getNonceFallback(address);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
catch {
|
|
3929
|
+
committedNonce = 0;
|
|
3930
|
+
}
|
|
3931
|
+
if (committedNonce >= nonce)
|
|
3919
3932
|
throw new Error(`a transaction with the same nonce already exists`);
|
|
3933
|
+
// Only reject exact duplicates already in the pool (not "higher nonce" rejections)
|
|
3920
3934
|
let transactions = await globalThis.transactionPoolStore.values();
|
|
3921
3935
|
transactions = await this.promiseTransactions(transactions);
|
|
3922
3936
|
transactions = transactions.filter((tx) => tx.decoded.from === address);
|
|
@@ -5041,11 +5055,6 @@ class Jobber {
|
|
|
5041
5055
|
}
|
|
5042
5056
|
}
|
|
5043
5057
|
|
|
5044
|
-
utils.addCodec({
|
|
5045
|
-
name: 'last-block-message',
|
|
5046
|
-
codec: 0x6c626d,
|
|
5047
|
-
hashAlg: 'keccak-256'
|
|
5048
|
-
});
|
|
5049
5058
|
const debug$1 = createDebugger('leofcoin/state');
|
|
5050
5059
|
class State extends Contract {
|
|
5051
5060
|
#resolveErrored;
|
|
@@ -5607,6 +5616,8 @@ class State extends Contract {
|
|
|
5607
5616
|
}
|
|
5608
5617
|
async #getLatestBlock() {
|
|
5609
5618
|
let promises = [];
|
|
5619
|
+
const connectedPeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected);
|
|
5620
|
+
let compatiblePeerCount = 0;
|
|
5610
5621
|
let data = await new globalThis.peernet.protos['peernet-request']({
|
|
5611
5622
|
request: 'lastBlock'
|
|
5612
5623
|
});
|
|
@@ -5614,15 +5625,8 @@ class State extends Contract {
|
|
|
5614
5625
|
for (const id in globalThis.peernet.connections) {
|
|
5615
5626
|
// @ts-ignore
|
|
5616
5627
|
const peer = globalThis.peernet.connections[id];
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
if (!peer.version || !this.version)
|
|
5620
|
-
return false;
|
|
5621
|
-
const [peerMajor, peerMinor] = peer.version.split('.');
|
|
5622
|
-
const [localMajor, localMinor] = this.version.split('.');
|
|
5623
|
-
return peerMajor === localMajor && peerMinor === localMinor;
|
|
5624
|
-
};
|
|
5625
|
-
if (peer.connected && isVersionCompatible()) {
|
|
5628
|
+
if (peer.connected && this.isVersionCompatible(peer.version)) {
|
|
5629
|
+
compatiblePeerCount += 1;
|
|
5626
5630
|
const task = async () => {
|
|
5627
5631
|
try {
|
|
5628
5632
|
const result = await peer.request(node.encoded);
|
|
@@ -5639,9 +5643,15 @@ class State extends Contract {
|
|
|
5639
5643
|
promises.push(task());
|
|
5640
5644
|
}
|
|
5641
5645
|
}
|
|
5646
|
+
if (connectedPeers.length > 0 && compatiblePeerCount === 0) {
|
|
5647
|
+
throw new ResolveError(`latestBlock: no compatible peers found for local version ${this.version} among ${connectedPeers.length} connected peers`);
|
|
5648
|
+
}
|
|
5642
5649
|
// @ts-ignore
|
|
5643
5650
|
console.log({ promises });
|
|
5644
5651
|
promises = (await this.promiseRequests(promises));
|
|
5652
|
+
if (compatiblePeerCount > 0 && promises.length === 0) {
|
|
5653
|
+
throw new ResolveError('latestBlock: no responses from compatible peers');
|
|
5654
|
+
}
|
|
5645
5655
|
console.log({ promises });
|
|
5646
5656
|
let latest = { index: 0, hash: '0x0', previousHash: '0x0' };
|
|
5647
5657
|
promises = promises.sort((a, b) => b.index - a.index);
|
|
@@ -5656,15 +5666,7 @@ class State extends Contract {
|
|
|
5656
5666
|
throw new Error('invalid block @getLatestBlock');
|
|
5657
5667
|
latest = { ...message.decoded, hash };
|
|
5658
5668
|
const peer = promises[0].peer;
|
|
5659
|
-
|
|
5660
|
-
const isVersionCompatible = () => {
|
|
5661
|
-
if (!peer.version || !this.version)
|
|
5662
|
-
return false;
|
|
5663
|
-
const [peerMajor, peerMinor] = peer.version.split('.');
|
|
5664
|
-
const [localMajor, localMinor] = this.version.split('.');
|
|
5665
|
-
return peerMajor === localMajor && peerMinor === localMinor;
|
|
5666
|
-
};
|
|
5667
|
-
if (peer.connected && isVersionCompatible()) {
|
|
5669
|
+
if (peer.connected && this.isVersionCompatible(peer.version)) {
|
|
5668
5670
|
let data = await new globalThis.peernet.protos['peernet-request']({
|
|
5669
5671
|
request: 'knownBlocks'
|
|
5670
5672
|
});
|
|
@@ -5812,7 +5814,7 @@ class State extends Contract {
|
|
|
5812
5814
|
if (this.#chainSyncing)
|
|
5813
5815
|
return false;
|
|
5814
5816
|
// Check if we have any connected peers with the same version
|
|
5815
|
-
const compatiblePeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && peer.version
|
|
5817
|
+
const compatiblePeers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && this.isVersionCompatible(peer.version));
|
|
5816
5818
|
if (compatiblePeers.length === 0) {
|
|
5817
5819
|
debug$1('No compatible peers available for sync');
|
|
5818
5820
|
return false;
|
|
@@ -5828,7 +5830,7 @@ class State extends Contract {
|
|
|
5828
5830
|
async #waitForPeers(timeoutMs = 30000) {
|
|
5829
5831
|
return new Promise((resolve) => {
|
|
5830
5832
|
const checkPeers = () => {
|
|
5831
|
-
const peers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && peer.version
|
|
5833
|
+
const peers = Object.values(globalThis.peernet.connections || {}).filter((peer) => peer.connected && this.isVersionCompatible(peer.version));
|
|
5832
5834
|
if (peers.length > 0) {
|
|
5833
5835
|
resolve(true);
|
|
5834
5836
|
}
|
|
@@ -6147,7 +6149,7 @@ class ConnectionMonitor {
|
|
|
6147
6149
|
const networkName = globalThis.peernet?.network;
|
|
6148
6150
|
if (networkName && typeof networkName === 'string') {
|
|
6149
6151
|
// Try to import network config
|
|
6150
|
-
const { default: networks } = await import('./constants-
|
|
6152
|
+
const { default: networks } = await import('./constants-D_XqG46B.js').then(function (n) { return n.n; });
|
|
6151
6153
|
const [mainKey, subKey] = networkName.split(':');
|
|
6152
6154
|
const networkConfig = networks?.[mainKey]?.[subKey];
|
|
6153
6155
|
if (networkConfig?.stars && Array.isArray(networkConfig.stars)) {
|
|
@@ -6239,16 +6241,6 @@ class ConnectionMonitor {
|
|
|
6239
6241
|
}
|
|
6240
6242
|
}
|
|
6241
6243
|
|
|
6242
|
-
utils.addCodec({
|
|
6243
|
-
name: 'last-block-message',
|
|
6244
|
-
codec: 0x6c626d,
|
|
6245
|
-
hashAlg: 'keccak-256'
|
|
6246
|
-
});
|
|
6247
|
-
utils.addCodec({
|
|
6248
|
-
name: 'last-block-request-message',
|
|
6249
|
-
codec: 0x6c62726d,
|
|
6250
|
-
hashAlg: 'keccak-256'
|
|
6251
|
-
});
|
|
6252
6244
|
const debug = createDebugger('leofcoin/chain');
|
|
6253
6245
|
// check if browser or local
|
|
6254
6246
|
class Chain extends VersionControl {
|
|
@@ -6342,7 +6334,10 @@ class Chain extends VersionControl {
|
|
|
6342
6334
|
return;
|
|
6343
6335
|
this.#castedVotes.add(voteKey);
|
|
6344
6336
|
const from = peernet.selectedAccount;
|
|
6345
|
-
const
|
|
6337
|
+
const voteData = { blockHash, index: BigInt(index), round: BigInt(round), from };
|
|
6338
|
+
const Message = type === 'prevote' ? PrevoteMessage : PrecommitMessage;
|
|
6339
|
+
const message = new Message(voteData);
|
|
6340
|
+
const payload = message.encoded;
|
|
6346
6341
|
try {
|
|
6347
6342
|
globalThis.peernet.publish(`consensus:${type}`, payload);
|
|
6348
6343
|
}
|
|
@@ -6357,16 +6352,17 @@ class Chain extends VersionControl {
|
|
|
6357
6352
|
*/
|
|
6358
6353
|
this.#handleProposal = async (payload) => {
|
|
6359
6354
|
try {
|
|
6360
|
-
const
|
|
6355
|
+
const message = new ProposalMessage(payload);
|
|
6356
|
+
const msg = message.decoded;
|
|
6361
6357
|
const { blockHash, index, round, from } = msg;
|
|
6362
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6363
|
-
const expectedProposerIdx = (index + round) % validators.length;
|
|
6358
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6359
|
+
const expectedProposerIdx = Number((index + round) % BigInt(validators.length));
|
|
6364
6360
|
if (!validators[expectedProposerIdx] || validators[expectedProposerIdx] !== from) {
|
|
6365
6361
|
debug(`[consensus] Proposal from wrong proposer at height ${index} round ${round}`);
|
|
6366
6362
|
return;
|
|
6367
6363
|
}
|
|
6368
6364
|
const localBlock = await this.lastBlock;
|
|
6369
|
-
const localIndex = localBlock?.index !== undefined ?
|
|
6365
|
+
const localIndex = localBlock?.index !== undefined ? localBlock.index : -1n;
|
|
6370
6366
|
if (index <= localIndex) {
|
|
6371
6367
|
debug(`[consensus] Ignoring stale proposal at height ${index} (local: ${localIndex})`);
|
|
6372
6368
|
return;
|
|
@@ -6385,13 +6381,13 @@ class Chain extends VersionControl {
|
|
|
6385
6381
|
debug(`[consensus] Cannot fetch proposed block ${blockHash}:`, e?.message);
|
|
6386
6382
|
return;
|
|
6387
6383
|
}
|
|
6388
|
-
this.#consensusRound = round;
|
|
6384
|
+
this.#consensusRound = Number(round);
|
|
6389
6385
|
if (this.#roundTimer) {
|
|
6390
6386
|
clearTimeout(this.#roundTimer);
|
|
6391
6387
|
this.#roundTimer = null;
|
|
6392
6388
|
}
|
|
6393
6389
|
if (validators.includes(peernet.selectedAccount) && !this.#isJailed(peernet.selectedAccount)) {
|
|
6394
|
-
await this.#castVote('prevote', blockHash, index, round);
|
|
6390
|
+
await this.#castVote('prevote', blockHash, Number(index), Number(round));
|
|
6395
6391
|
}
|
|
6396
6392
|
}
|
|
6397
6393
|
catch (e) {
|
|
@@ -6404,13 +6400,14 @@ class Chain extends VersionControl {
|
|
|
6404
6400
|
*/
|
|
6405
6401
|
this.#handlePrevote = async (payload) => {
|
|
6406
6402
|
try {
|
|
6407
|
-
const
|
|
6403
|
+
const message = new PrevoteMessage(payload);
|
|
6404
|
+
const msg = message.decoded;
|
|
6408
6405
|
const { blockHash, index, round, from } = msg;
|
|
6409
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6406
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6410
6407
|
if (!validators.includes(from))
|
|
6411
6408
|
return;
|
|
6412
6409
|
const localBlock = await this.lastBlock;
|
|
6413
|
-
const localIndex = localBlock?.index !== undefined ?
|
|
6410
|
+
const localIndex = localBlock?.index !== undefined ? localBlock.index : -1n;
|
|
6414
6411
|
if (index <= localIndex)
|
|
6415
6412
|
return;
|
|
6416
6413
|
const voteKey = `${index}:${round}:${blockHash}`;
|
|
@@ -6423,7 +6420,7 @@ class Chain extends VersionControl {
|
|
|
6423
6420
|
if (voteCount >= threshold &&
|
|
6424
6421
|
validators.includes(peernet.selectedAccount) &&
|
|
6425
6422
|
!this.#isJailed(peernet.selectedAccount)) {
|
|
6426
|
-
await this.#castVote('precommit', blockHash, index, round);
|
|
6423
|
+
await this.#castVote('precommit', blockHash, Number(index), Number(round));
|
|
6427
6424
|
}
|
|
6428
6425
|
}
|
|
6429
6426
|
catch (e) {
|
|
@@ -6437,12 +6434,13 @@ class Chain extends VersionControl {
|
|
|
6437
6434
|
*/
|
|
6438
6435
|
this.#handlePrecommit = async (payload) => {
|
|
6439
6436
|
try {
|
|
6440
|
-
const
|
|
6437
|
+
const message = new PrecommitMessage(payload);
|
|
6438
|
+
const msg = message.decoded;
|
|
6441
6439
|
const { blockHash, index, round, from } = msg;
|
|
6442
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6440
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6443
6441
|
if (!validators.includes(from))
|
|
6444
6442
|
return;
|
|
6445
|
-
if (index <= this.#committedHeight)
|
|
6443
|
+
if (index <= BigInt(this.#committedHeight))
|
|
6446
6444
|
return;
|
|
6447
6445
|
const voteKey = `${index}:${round}:${blockHash}`;
|
|
6448
6446
|
if (!this.#precommits.has(voteKey))
|
|
@@ -6451,27 +6449,27 @@ class Chain extends VersionControl {
|
|
|
6451
6449
|
const threshold = Math.ceil((2 * validators.length) / 3);
|
|
6452
6450
|
const voteCount = this.#precommits.get(voteKey).size;
|
|
6453
6451
|
debug(`[consensus] Precommits ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`);
|
|
6454
|
-
if (voteCount >= threshold && index > this.#committedHeight) {
|
|
6455
|
-
this.#committedHeight = index;
|
|
6452
|
+
if (voteCount >= threshold && index > BigInt(this.#committedHeight)) {
|
|
6453
|
+
this.#committedHeight = Number(index);
|
|
6456
6454
|
this.#consensusRound = 0;
|
|
6457
6455
|
// Prune vote state for committed and older heights
|
|
6458
6456
|
for (const key of [...this.#prevotes.keys()]) {
|
|
6459
|
-
if (
|
|
6457
|
+
if (BigInt(key.split(':')[0]) <= index)
|
|
6460
6458
|
this.#prevotes.delete(key);
|
|
6461
6459
|
}
|
|
6462
6460
|
for (const key of [...this.#precommits.keys()]) {
|
|
6463
|
-
if (
|
|
6461
|
+
if (BigInt(key.split(':')[0]) <= index)
|
|
6464
6462
|
this.#precommits.delete(key);
|
|
6465
6463
|
}
|
|
6466
6464
|
for (const key of [...this.#castedVotes]) {
|
|
6467
|
-
if (
|
|
6465
|
+
if (BigInt(key.split(':')[1]) <= index)
|
|
6468
6466
|
this.#castedVotes.delete(key);
|
|
6469
6467
|
}
|
|
6470
6468
|
// Non-proposers add the block to local state now.
|
|
6471
6469
|
// Proposers already committed state in #createBlock() and their
|
|
6472
6470
|
// lastBlock.index === index, so the guard below skips them.
|
|
6473
6471
|
const currentBlock = await this.lastBlock;
|
|
6474
|
-
const currentIndex = currentBlock?.index !== undefined ?
|
|
6472
|
+
const currentIndex = currentBlock?.index !== undefined ? currentBlock.index : -1n;
|
|
6475
6473
|
if (index > currentIndex) {
|
|
6476
6474
|
debug(`[consensus] ✅ Committing block ${blockHash} at height ${index}`);
|
|
6477
6475
|
try {
|
|
@@ -6744,7 +6742,9 @@ class Chain extends VersionControl {
|
|
|
6744
6742
|
await globalThis.peernet.addRequestHandler('transactionPool', this.#transactionPoolHandler.bind(this));
|
|
6745
6743
|
await globalThis.peernet.addRequestHandler('version', this.#versionHandler.bind(this));
|
|
6746
6744
|
await globalThis.peernet.addRequestHandler('stateInfo', () => {
|
|
6747
|
-
return new globalThis.peernet.protos['peernet-response']({
|
|
6745
|
+
return new globalThis.peernet.protos['peernet-response']({
|
|
6746
|
+
response: new StateMessage(this.machine.states.info).encoded
|
|
6747
|
+
});
|
|
6748
6748
|
});
|
|
6749
6749
|
globalThis.peernet.subscribe('add-block', this.#addBlock.bind(this));
|
|
6750
6750
|
globalThis.peernet.subscribe('invalid-transaction', this.#invalidTransaction.bind(this));
|
|
@@ -6832,13 +6832,8 @@ class Chain extends VersionControl {
|
|
|
6832
6832
|
async getPeerTransactionPool(peer) {
|
|
6833
6833
|
let transactionsInPool = await this.#makeRequest(peer, 'transactionPool');
|
|
6834
6834
|
if (transactionsInPool instanceof Uint8Array) {
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
transactionsInPool = JSON.parse(text);
|
|
6838
|
-
}
|
|
6839
|
-
catch (e) {
|
|
6840
|
-
return [];
|
|
6841
|
-
}
|
|
6835
|
+
debug('transactionPool response must be decoded array payload');
|
|
6836
|
+
return [];
|
|
6842
6837
|
}
|
|
6843
6838
|
if (!Array.isArray(transactionsInPool))
|
|
6844
6839
|
return [];
|
|
@@ -6862,9 +6857,41 @@ class Chain extends VersionControl {
|
|
|
6862
6857
|
async #peerConnected(peerId) {
|
|
6863
6858
|
debug(`peer connected: ${peerId}`);
|
|
6864
6859
|
const peer = peernet.getConnection(peerId);
|
|
6860
|
+
if (!peer) {
|
|
6861
|
+
debug(`peer not found: ${peerId}`);
|
|
6862
|
+
return;
|
|
6863
|
+
}
|
|
6864
|
+
if (!peer.version) {
|
|
6865
|
+
try {
|
|
6866
|
+
let versionResponse = await this.#makeRequest(peer, 'version');
|
|
6867
|
+
if (versionResponse instanceof Uint8Array) {
|
|
6868
|
+
versionResponse = new TextDecoder().decode(versionResponse);
|
|
6869
|
+
}
|
|
6870
|
+
if (typeof versionResponse === 'string') {
|
|
6871
|
+
peer.version = versionResponse;
|
|
6872
|
+
}
|
|
6873
|
+
else if (versionResponse &&
|
|
6874
|
+
typeof versionResponse === 'object' &&
|
|
6875
|
+
typeof versionResponse.version === 'string') {
|
|
6876
|
+
peer.version = versionResponse.version;
|
|
6877
|
+
}
|
|
6878
|
+
if (!peer.version || typeof peer.version !== 'string') {
|
|
6879
|
+
const reason = `invalid version response from peer ${peerId}`;
|
|
6880
|
+
debug(reason);
|
|
6881
|
+
await this.#recordPeerFailure(peerId, reason);
|
|
6882
|
+
return;
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
catch (error) {
|
|
6886
|
+
debug(`failed to request version from peer ${peerId}:`, error?.message ?? error);
|
|
6887
|
+
return;
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
6865
6890
|
debug(`peer connected with version ${peer.version}`);
|
|
6866
6891
|
if (!this.isVersionCompatible(peer.version)) {
|
|
6867
|
-
|
|
6892
|
+
const mismatchReason = `incompatible peer version ${peer.version} (local: ${this.version})`;
|
|
6893
|
+
console.error(`[chain] ${mismatchReason}`);
|
|
6894
|
+
await this.#recordPeerFailure(peerId, mismatchReason);
|
|
6868
6895
|
return;
|
|
6869
6896
|
}
|
|
6870
6897
|
let lastBlock;
|
|
@@ -6884,7 +6911,7 @@ class Chain extends VersionControl {
|
|
|
6884
6911
|
// This prevents Byzantine nodes from claiming a fake chain length to steer our sync
|
|
6885
6912
|
const localBlock = await this.lastBlock;
|
|
6886
6913
|
const MAX_SYNC_AHEAD = 100_000;
|
|
6887
|
-
if (lastBlock?.index > (localBlock?.index ?? 0) + MAX_SYNC_AHEAD) {
|
|
6914
|
+
if (lastBlock?.index > BigInt(localBlock?.index ?? 0) + BigInt(MAX_SYNC_AHEAD)) {
|
|
6888
6915
|
const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown';
|
|
6889
6916
|
debug(`Peer ${peerName} claims unreasonable block height ${lastBlock.index} (local: ${localBlock?.index ?? 0})`);
|
|
6890
6917
|
await this.#recordPeerFailure(peerId, `unreasonable lastBlock index: ${lastBlock.index}`);
|
|
@@ -6900,15 +6927,13 @@ class Chain extends VersionControl {
|
|
|
6900
6927
|
try {
|
|
6901
6928
|
let knownBlocksResponse = await this.#makeRequest(peer, 'knownBlocks');
|
|
6902
6929
|
if (knownBlocksResponse instanceof Uint8Array) {
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
console.log(e);
|
|
6908
|
-
}
|
|
6930
|
+
const reason = `knownBlocks must be object response, got raw bytes from ${peerId}`;
|
|
6931
|
+
debug(reason);
|
|
6932
|
+
await this.#recordPeerFailure(peerId, reason);
|
|
6933
|
+
return;
|
|
6909
6934
|
}
|
|
6910
6935
|
const MAX_WANTLIST_SIZE = 1000;
|
|
6911
|
-
if (knownBlocksResponse.blocks) {
|
|
6936
|
+
if (knownBlocksResponse && Array.isArray(knownBlocksResponse.blocks)) {
|
|
6912
6937
|
const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
|
|
6913
6938
|
if (remaining > 0) {
|
|
6914
6939
|
for (const hash of knownBlocksResponse.blocks.slice(0, remaining)) {
|
|
@@ -6950,12 +6975,7 @@ class Chain extends VersionControl {
|
|
|
6950
6975
|
try {
|
|
6951
6976
|
let stateInfo = await this.#makeRequest(peer, 'stateInfo');
|
|
6952
6977
|
if (stateInfo instanceof Uint8Array) {
|
|
6953
|
-
|
|
6954
|
-
stateInfo = JSON.parse(new TextDecoder().decode(stateInfo));
|
|
6955
|
-
}
|
|
6956
|
-
catch (e) {
|
|
6957
|
-
console.log(e);
|
|
6958
|
-
}
|
|
6978
|
+
stateInfo = new StateMessage(stateInfo).decoded;
|
|
6959
6979
|
}
|
|
6960
6980
|
await this.syncChain(lastBlock);
|
|
6961
6981
|
this.machine.states.info = stateInfo;
|
|
@@ -6973,7 +6993,7 @@ class Chain extends VersionControl {
|
|
|
6973
6993
|
return new globalThis.peernet.protos['peernet-response']({ response: pool });
|
|
6974
6994
|
}
|
|
6975
6995
|
async #versionHandler() {
|
|
6976
|
-
return new globalThis.peernet.protos['peernet-response']({ response:
|
|
6996
|
+
return new globalThis.peernet.protos['peernet-response']({ response: this.version });
|
|
6977
6997
|
}
|
|
6978
6998
|
async #executeTransaction({ hash, from, to, method, params, nonce }) {
|
|
6979
6999
|
try {
|
|
@@ -7325,12 +7345,14 @@ class Chain extends VersionControl {
|
|
|
7325
7345
|
debug(`created block: ${hash} @${block.index}`);
|
|
7326
7346
|
// Phase 2: announce proposal for consensus voting instead of direct add-block
|
|
7327
7347
|
console.log(`[consensus] 📤 Proposing block #${block.index} | hash: ${hash} | round: ${this.#consensusRound}`);
|
|
7328
|
-
const
|
|
7348
|
+
const proposalData = {
|
|
7329
7349
|
blockHash: hash,
|
|
7330
|
-
index: block.index,
|
|
7331
|
-
round: this.#consensusRound,
|
|
7350
|
+
index: BigInt(block.index),
|
|
7351
|
+
round: BigInt(this.#consensusRound),
|
|
7332
7352
|
from: peernet.selectedAccount
|
|
7333
|
-
}
|
|
7353
|
+
};
|
|
7354
|
+
const proposalMessage = new ProposalMessage(proposalData);
|
|
7355
|
+
const proposalPayload = proposalMessage.encoded;
|
|
7334
7356
|
try {
|
|
7335
7357
|
globalThis.peernet.publish('consensus:propose', proposalPayload);
|
|
7336
7358
|
}
|