@leofcoin/chain 1.9.3 → 1.9.5
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 +71 -72
- package/exports/browser/{constants-BTdMMS4w.js → constants-M3qbPwZp.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 +71 -72
- 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 +3 -2
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, u as utils, b as PrevoteMessage, c as PrecommitMessage, d as ProposalMessage, e as BWMessage, S as StateMessage, f as BWRequestMessage } from './constants-M3qbPwZp.js';
|
|
2
2
|
import { log } from 'console';
|
|
3
3
|
import { log as log$1 } from 'node:console';
|
|
4
4
|
|
|
@@ -5055,11 +5055,6 @@ class Jobber {
|
|
|
5055
5055
|
}
|
|
5056
5056
|
}
|
|
5057
5057
|
|
|
5058
|
-
utils.addCodec({
|
|
5059
|
-
name: 'last-block-message',
|
|
5060
|
-
codec: 0x6c626d,
|
|
5061
|
-
hashAlg: 'keccak-256'
|
|
5062
|
-
});
|
|
5063
5058
|
const debug$1 = createDebugger('leofcoin/state');
|
|
5064
5059
|
class State extends Contract {
|
|
5065
5060
|
#resolveErrored;
|
|
@@ -6154,7 +6149,7 @@ class ConnectionMonitor {
|
|
|
6154
6149
|
const networkName = globalThis.peernet?.network;
|
|
6155
6150
|
if (networkName && typeof networkName === 'string') {
|
|
6156
6151
|
// Try to import network config
|
|
6157
|
-
const { default: networks } = await import('./constants-
|
|
6152
|
+
const { default: networks } = await import('./constants-M3qbPwZp.js').then(function (n) { return n.n; });
|
|
6158
6153
|
const [mainKey, subKey] = networkName.split(':');
|
|
6159
6154
|
const networkConfig = networks?.[mainKey]?.[subKey];
|
|
6160
6155
|
if (networkConfig?.stars && Array.isArray(networkConfig.stars)) {
|
|
@@ -6246,16 +6241,20 @@ class ConnectionMonitor {
|
|
|
6246
6241
|
}
|
|
6247
6242
|
}
|
|
6248
6243
|
|
|
6249
|
-
|
|
6250
|
-
name
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
}
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6244
|
+
const ensureCodec = (name, codec, hashAlg = 'keccak-256') => {
|
|
6245
|
+
if (!utils.codecs[name]) {
|
|
6246
|
+
utils.addCodec({ name, codec, hashAlg });
|
|
6247
|
+
}
|
|
6248
|
+
};
|
|
6249
|
+
// Backward compatibility for mixed deployments where some nodes still resolve
|
|
6250
|
+
// older @leofcoin/codecs versions that do not include these protocol codecs.
|
|
6251
|
+
ensureCodec('last-block-message', 0x6c626d);
|
|
6252
|
+
ensureCodec('last-block-request-message', 0x6c62726d);
|
|
6253
|
+
ensureCodec('state-message', 0x73746d);
|
|
6254
|
+
ensureCodec('publish-message', 0x70626d);
|
|
6255
|
+
ensureCodec('proposal-message', 0x70726d);
|
|
6256
|
+
ensureCodec('prevote-message', 0x70766d);
|
|
6257
|
+
ensureCodec('precommit-message', 0x7063636d);
|
|
6259
6258
|
const debug = createDebugger('leofcoin/chain');
|
|
6260
6259
|
// check if browser or local
|
|
6261
6260
|
class Chain extends VersionControl {
|
|
@@ -6349,7 +6348,10 @@ class Chain extends VersionControl {
|
|
|
6349
6348
|
return;
|
|
6350
6349
|
this.#castedVotes.add(voteKey);
|
|
6351
6350
|
const from = peernet.selectedAccount;
|
|
6352
|
-
const
|
|
6351
|
+
const voteData = { blockHash, index: BigInt(index), round: BigInt(round), from };
|
|
6352
|
+
const Message = type === 'prevote' ? PrevoteMessage : PrecommitMessage;
|
|
6353
|
+
const message = new Message(voteData);
|
|
6354
|
+
const payload = message.encoded;
|
|
6353
6355
|
try {
|
|
6354
6356
|
globalThis.peernet.publish(`consensus:${type}`, payload);
|
|
6355
6357
|
}
|
|
@@ -6364,16 +6366,17 @@ class Chain extends VersionControl {
|
|
|
6364
6366
|
*/
|
|
6365
6367
|
this.#handleProposal = async (payload) => {
|
|
6366
6368
|
try {
|
|
6367
|
-
const
|
|
6369
|
+
const message = new ProposalMessage(payload);
|
|
6370
|
+
const msg = message.decoded;
|
|
6368
6371
|
const { blockHash, index, round, from } = msg;
|
|
6369
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6370
|
-
const expectedProposerIdx = (index + round) % validators.length;
|
|
6372
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6373
|
+
const expectedProposerIdx = Number((index + round) % BigInt(validators.length));
|
|
6371
6374
|
if (!validators[expectedProposerIdx] || validators[expectedProposerIdx] !== from) {
|
|
6372
6375
|
debug(`[consensus] Proposal from wrong proposer at height ${index} round ${round}`);
|
|
6373
6376
|
return;
|
|
6374
6377
|
}
|
|
6375
6378
|
const localBlock = await this.lastBlock;
|
|
6376
|
-
const localIndex = localBlock?.index !== undefined ?
|
|
6379
|
+
const localIndex = localBlock?.index !== undefined ? localBlock.index : -1n;
|
|
6377
6380
|
if (index <= localIndex) {
|
|
6378
6381
|
debug(`[consensus] Ignoring stale proposal at height ${index} (local: ${localIndex})`);
|
|
6379
6382
|
return;
|
|
@@ -6392,13 +6395,13 @@ class Chain extends VersionControl {
|
|
|
6392
6395
|
debug(`[consensus] Cannot fetch proposed block ${blockHash}:`, e?.message);
|
|
6393
6396
|
return;
|
|
6394
6397
|
}
|
|
6395
|
-
this.#consensusRound = round;
|
|
6398
|
+
this.#consensusRound = Number(round);
|
|
6396
6399
|
if (this.#roundTimer) {
|
|
6397
6400
|
clearTimeout(this.#roundTimer);
|
|
6398
6401
|
this.#roundTimer = null;
|
|
6399
6402
|
}
|
|
6400
6403
|
if (validators.includes(peernet.selectedAccount) && !this.#isJailed(peernet.selectedAccount)) {
|
|
6401
|
-
await this.#castVote('prevote', blockHash, index, round);
|
|
6404
|
+
await this.#castVote('prevote', blockHash, Number(index), Number(round));
|
|
6402
6405
|
}
|
|
6403
6406
|
}
|
|
6404
6407
|
catch (e) {
|
|
@@ -6411,13 +6414,14 @@ class Chain extends VersionControl {
|
|
|
6411
6414
|
*/
|
|
6412
6415
|
this.#handlePrevote = async (payload) => {
|
|
6413
6416
|
try {
|
|
6414
|
-
const
|
|
6417
|
+
const message = new PrevoteMessage(payload);
|
|
6418
|
+
const msg = message.decoded;
|
|
6415
6419
|
const { blockHash, index, round, from } = msg;
|
|
6416
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6420
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6417
6421
|
if (!validators.includes(from))
|
|
6418
6422
|
return;
|
|
6419
6423
|
const localBlock = await this.lastBlock;
|
|
6420
|
-
const localIndex = localBlock?.index !== undefined ?
|
|
6424
|
+
const localIndex = localBlock?.index !== undefined ? localBlock.index : -1n;
|
|
6421
6425
|
if (index <= localIndex)
|
|
6422
6426
|
return;
|
|
6423
6427
|
const voteKey = `${index}:${round}:${blockHash}`;
|
|
@@ -6430,7 +6434,7 @@ class Chain extends VersionControl {
|
|
|
6430
6434
|
if (voteCount >= threshold &&
|
|
6431
6435
|
validators.includes(peernet.selectedAccount) &&
|
|
6432
6436
|
!this.#isJailed(peernet.selectedAccount)) {
|
|
6433
|
-
await this.#castVote('precommit', blockHash, index, round);
|
|
6437
|
+
await this.#castVote('precommit', blockHash, Number(index), Number(round));
|
|
6434
6438
|
}
|
|
6435
6439
|
}
|
|
6436
6440
|
catch (e) {
|
|
@@ -6444,12 +6448,13 @@ class Chain extends VersionControl {
|
|
|
6444
6448
|
*/
|
|
6445
6449
|
this.#handlePrecommit = async (payload) => {
|
|
6446
6450
|
try {
|
|
6447
|
-
const
|
|
6451
|
+
const message = new PrecommitMessage(payload);
|
|
6452
|
+
const msg = message.decoded;
|
|
6448
6453
|
const { blockHash, index, round, from } = msg;
|
|
6449
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6454
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6450
6455
|
if (!validators.includes(from))
|
|
6451
6456
|
return;
|
|
6452
|
-
if (index <= this.#committedHeight)
|
|
6457
|
+
if (index <= BigInt(this.#committedHeight))
|
|
6453
6458
|
return;
|
|
6454
6459
|
const voteKey = `${index}:${round}:${blockHash}`;
|
|
6455
6460
|
if (!this.#precommits.has(voteKey))
|
|
@@ -6458,27 +6463,27 @@ class Chain extends VersionControl {
|
|
|
6458
6463
|
const threshold = Math.ceil((2 * validators.length) / 3);
|
|
6459
6464
|
const voteCount = this.#precommits.get(voteKey).size;
|
|
6460
6465
|
debug(`[consensus] Precommits ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`);
|
|
6461
|
-
if (voteCount >= threshold && index > this.#committedHeight) {
|
|
6462
|
-
this.#committedHeight = index;
|
|
6466
|
+
if (voteCount >= threshold && index > BigInt(this.#committedHeight)) {
|
|
6467
|
+
this.#committedHeight = Number(index);
|
|
6463
6468
|
this.#consensusRound = 0;
|
|
6464
6469
|
// Prune vote state for committed and older heights
|
|
6465
6470
|
for (const key of [...this.#prevotes.keys()]) {
|
|
6466
|
-
if (
|
|
6471
|
+
if (BigInt(key.split(':')[0]) <= index)
|
|
6467
6472
|
this.#prevotes.delete(key);
|
|
6468
6473
|
}
|
|
6469
6474
|
for (const key of [...this.#precommits.keys()]) {
|
|
6470
|
-
if (
|
|
6475
|
+
if (BigInt(key.split(':')[0]) <= index)
|
|
6471
6476
|
this.#precommits.delete(key);
|
|
6472
6477
|
}
|
|
6473
6478
|
for (const key of [...this.#castedVotes]) {
|
|
6474
|
-
if (
|
|
6479
|
+
if (BigInt(key.split(':')[1]) <= index)
|
|
6475
6480
|
this.#castedVotes.delete(key);
|
|
6476
6481
|
}
|
|
6477
6482
|
// Non-proposers add the block to local state now.
|
|
6478
6483
|
// Proposers already committed state in #createBlock() and their
|
|
6479
6484
|
// lastBlock.index === index, so the guard below skips them.
|
|
6480
6485
|
const currentBlock = await this.lastBlock;
|
|
6481
|
-
const currentIndex = currentBlock?.index !== undefined ?
|
|
6486
|
+
const currentIndex = currentBlock?.index !== undefined ? currentBlock.index : -1n;
|
|
6482
6487
|
if (index > currentIndex) {
|
|
6483
6488
|
debug(`[consensus] ✅ Committing block ${blockHash} at height ${index}`);
|
|
6484
6489
|
try {
|
|
@@ -6751,7 +6756,9 @@ class Chain extends VersionControl {
|
|
|
6751
6756
|
await globalThis.peernet.addRequestHandler('transactionPool', this.#transactionPoolHandler.bind(this));
|
|
6752
6757
|
await globalThis.peernet.addRequestHandler('version', this.#versionHandler.bind(this));
|
|
6753
6758
|
await globalThis.peernet.addRequestHandler('stateInfo', () => {
|
|
6754
|
-
return new globalThis.peernet.protos['peernet-response']({
|
|
6759
|
+
return new globalThis.peernet.protos['peernet-response']({
|
|
6760
|
+
response: new StateMessage(this.machine.states.info).encoded
|
|
6761
|
+
});
|
|
6755
6762
|
});
|
|
6756
6763
|
globalThis.peernet.subscribe('add-block', this.#addBlock.bind(this));
|
|
6757
6764
|
globalThis.peernet.subscribe('invalid-transaction', this.#invalidTransaction.bind(this));
|
|
@@ -6839,13 +6846,8 @@ class Chain extends VersionControl {
|
|
|
6839
6846
|
async getPeerTransactionPool(peer) {
|
|
6840
6847
|
let transactionsInPool = await this.#makeRequest(peer, 'transactionPool');
|
|
6841
6848
|
if (transactionsInPool instanceof Uint8Array) {
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
transactionsInPool = JSON.parse(text);
|
|
6845
|
-
}
|
|
6846
|
-
catch (e) {
|
|
6847
|
-
return [];
|
|
6848
|
-
}
|
|
6849
|
+
debug('transactionPool response must be decoded array payload');
|
|
6850
|
+
return [];
|
|
6849
6851
|
}
|
|
6850
6852
|
if (!Array.isArray(transactionsInPool))
|
|
6851
6853
|
return [];
|
|
@@ -6877,13 +6879,7 @@ class Chain extends VersionControl {
|
|
|
6877
6879
|
try {
|
|
6878
6880
|
let versionResponse = await this.#makeRequest(peer, 'version');
|
|
6879
6881
|
if (versionResponse instanceof Uint8Array) {
|
|
6880
|
-
|
|
6881
|
-
try {
|
|
6882
|
-
versionResponse = JSON.parse(decoded);
|
|
6883
|
-
}
|
|
6884
|
-
catch {
|
|
6885
|
-
versionResponse = decoded;
|
|
6886
|
-
}
|
|
6882
|
+
versionResponse = new TextDecoder().decode(versionResponse);
|
|
6887
6883
|
}
|
|
6888
6884
|
if (typeof versionResponse === 'string') {
|
|
6889
6885
|
peer.version = versionResponse;
|
|
@@ -6893,6 +6889,12 @@ class Chain extends VersionControl {
|
|
|
6893
6889
|
typeof versionResponse.version === 'string') {
|
|
6894
6890
|
peer.version = versionResponse.version;
|
|
6895
6891
|
}
|
|
6892
|
+
if (!peer.version || typeof peer.version !== 'string') {
|
|
6893
|
+
const reason = `invalid version response from peer ${peerId}`;
|
|
6894
|
+
debug(reason);
|
|
6895
|
+
await this.#recordPeerFailure(peerId, reason);
|
|
6896
|
+
return;
|
|
6897
|
+
}
|
|
6896
6898
|
}
|
|
6897
6899
|
catch (error) {
|
|
6898
6900
|
debug(`failed to request version from peer ${peerId}:`, error?.message ?? error);
|
|
@@ -6901,7 +6903,9 @@ class Chain extends VersionControl {
|
|
|
6901
6903
|
}
|
|
6902
6904
|
debug(`peer connected with version ${peer.version}`);
|
|
6903
6905
|
if (!this.isVersionCompatible(peer.version)) {
|
|
6904
|
-
|
|
6906
|
+
const mismatchReason = `incompatible peer version ${peer.version} (local: ${this.version})`;
|
|
6907
|
+
console.error(`[chain] ${mismatchReason}`);
|
|
6908
|
+
await this.#recordPeerFailure(peerId, mismatchReason);
|
|
6905
6909
|
return;
|
|
6906
6910
|
}
|
|
6907
6911
|
let lastBlock;
|
|
@@ -6921,7 +6925,7 @@ class Chain extends VersionControl {
|
|
|
6921
6925
|
// This prevents Byzantine nodes from claiming a fake chain length to steer our sync
|
|
6922
6926
|
const localBlock = await this.lastBlock;
|
|
6923
6927
|
const MAX_SYNC_AHEAD = 100_000;
|
|
6924
|
-
if (lastBlock?.index > (localBlock?.index ?? 0) + MAX_SYNC_AHEAD) {
|
|
6928
|
+
if (lastBlock?.index > BigInt(localBlock?.index ?? 0) + BigInt(MAX_SYNC_AHEAD)) {
|
|
6925
6929
|
const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown';
|
|
6926
6930
|
debug(`Peer ${peerName} claims unreasonable block height ${lastBlock.index} (local: ${localBlock?.index ?? 0})`);
|
|
6927
6931
|
await this.#recordPeerFailure(peerId, `unreasonable lastBlock index: ${lastBlock.index}`);
|
|
@@ -6937,15 +6941,13 @@ class Chain extends VersionControl {
|
|
|
6937
6941
|
try {
|
|
6938
6942
|
let knownBlocksResponse = await this.#makeRequest(peer, 'knownBlocks');
|
|
6939
6943
|
if (knownBlocksResponse instanceof Uint8Array) {
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
console.log(e);
|
|
6945
|
-
}
|
|
6944
|
+
const reason = `knownBlocks must be object response, got raw bytes from ${peerId}`;
|
|
6945
|
+
debug(reason);
|
|
6946
|
+
await this.#recordPeerFailure(peerId, reason);
|
|
6947
|
+
return;
|
|
6946
6948
|
}
|
|
6947
6949
|
const MAX_WANTLIST_SIZE = 1000;
|
|
6948
|
-
if (knownBlocksResponse.blocks) {
|
|
6950
|
+
if (knownBlocksResponse && Array.isArray(knownBlocksResponse.blocks)) {
|
|
6949
6951
|
const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
|
|
6950
6952
|
if (remaining > 0) {
|
|
6951
6953
|
for (const hash of knownBlocksResponse.blocks.slice(0, remaining)) {
|
|
@@ -6987,12 +6989,7 @@ class Chain extends VersionControl {
|
|
|
6987
6989
|
try {
|
|
6988
6990
|
let stateInfo = await this.#makeRequest(peer, 'stateInfo');
|
|
6989
6991
|
if (stateInfo instanceof Uint8Array) {
|
|
6990
|
-
|
|
6991
|
-
stateInfo = JSON.parse(new TextDecoder().decode(stateInfo));
|
|
6992
|
-
}
|
|
6993
|
-
catch (e) {
|
|
6994
|
-
console.log(e);
|
|
6995
|
-
}
|
|
6992
|
+
stateInfo = new StateMessage(stateInfo).decoded;
|
|
6996
6993
|
}
|
|
6997
6994
|
await this.syncChain(lastBlock);
|
|
6998
6995
|
this.machine.states.info = stateInfo;
|
|
@@ -7010,7 +7007,7 @@ class Chain extends VersionControl {
|
|
|
7010
7007
|
return new globalThis.peernet.protos['peernet-response']({ response: pool });
|
|
7011
7008
|
}
|
|
7012
7009
|
async #versionHandler() {
|
|
7013
|
-
return new globalThis.peernet.protos['peernet-response']({ response:
|
|
7010
|
+
return new globalThis.peernet.protos['peernet-response']({ response: this.version });
|
|
7014
7011
|
}
|
|
7015
7012
|
async #executeTransaction({ hash, from, to, method, params, nonce }) {
|
|
7016
7013
|
try {
|
|
@@ -7362,12 +7359,14 @@ class Chain extends VersionControl {
|
|
|
7362
7359
|
debug(`created block: ${hash} @${block.index}`);
|
|
7363
7360
|
// Phase 2: announce proposal for consensus voting instead of direct add-block
|
|
7364
7361
|
console.log(`[consensus] 📤 Proposing block #${block.index} | hash: ${hash} | round: ${this.#consensusRound}`);
|
|
7365
|
-
const
|
|
7362
|
+
const proposalData = {
|
|
7366
7363
|
blockHash: hash,
|
|
7367
|
-
index: block.index,
|
|
7368
|
-
round: this.#consensusRound,
|
|
7364
|
+
index: BigInt(block.index),
|
|
7365
|
+
round: BigInt(this.#consensusRound),
|
|
7369
7366
|
from: peernet.selectedAccount
|
|
7370
|
-
}
|
|
7367
|
+
};
|
|
7368
|
+
const proposalMessage = new ProposalMessage(proposalData);
|
|
7369
|
+
const proposalPayload = proposalMessage.encoded;
|
|
7371
7370
|
try {
|
|
7372
7371
|
globalThis.peernet.publish('consensus:propose', proposalPayload);
|
|
7373
7372
|
}
|