@leofcoin/chain 1.9.3 → 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 +57 -72
- 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 +56 -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 +2 -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, 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
|
|
|
@@ -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-D_XqG46B.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,6 @@ class ConnectionMonitor {
|
|
|
6246
6241
|
}
|
|
6247
6242
|
}
|
|
6248
6243
|
|
|
6249
|
-
utils.addCodec({
|
|
6250
|
-
name: 'last-block-message',
|
|
6251
|
-
codec: 0x6c626d,
|
|
6252
|
-
hashAlg: 'keccak-256'
|
|
6253
|
-
});
|
|
6254
|
-
utils.addCodec({
|
|
6255
|
-
name: 'last-block-request-message',
|
|
6256
|
-
codec: 0x6c62726d,
|
|
6257
|
-
hashAlg: 'keccak-256'
|
|
6258
|
-
});
|
|
6259
6244
|
const debug = createDebugger('leofcoin/chain');
|
|
6260
6245
|
// check if browser or local
|
|
6261
6246
|
class Chain extends VersionControl {
|
|
@@ -6349,7 +6334,10 @@ class Chain extends VersionControl {
|
|
|
6349
6334
|
return;
|
|
6350
6335
|
this.#castedVotes.add(voteKey);
|
|
6351
6336
|
const from = peernet.selectedAccount;
|
|
6352
|
-
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;
|
|
6353
6341
|
try {
|
|
6354
6342
|
globalThis.peernet.publish(`consensus:${type}`, payload);
|
|
6355
6343
|
}
|
|
@@ -6364,16 +6352,17 @@ class Chain extends VersionControl {
|
|
|
6364
6352
|
*/
|
|
6365
6353
|
this.#handleProposal = async (payload) => {
|
|
6366
6354
|
try {
|
|
6367
|
-
const
|
|
6355
|
+
const message = new ProposalMessage(payload);
|
|
6356
|
+
const msg = message.decoded;
|
|
6368
6357
|
const { blockHash, index, round, from } = msg;
|
|
6369
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6370
|
-
const expectedProposerIdx = (index + round) % validators.length;
|
|
6358
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6359
|
+
const expectedProposerIdx = Number((index + round) % BigInt(validators.length));
|
|
6371
6360
|
if (!validators[expectedProposerIdx] || validators[expectedProposerIdx] !== from) {
|
|
6372
6361
|
debug(`[consensus] Proposal from wrong proposer at height ${index} round ${round}`);
|
|
6373
6362
|
return;
|
|
6374
6363
|
}
|
|
6375
6364
|
const localBlock = await this.lastBlock;
|
|
6376
|
-
const localIndex = localBlock?.index !== undefined ?
|
|
6365
|
+
const localIndex = localBlock?.index !== undefined ? localBlock.index : -1n;
|
|
6377
6366
|
if (index <= localIndex) {
|
|
6378
6367
|
debug(`[consensus] Ignoring stale proposal at height ${index} (local: ${localIndex})`);
|
|
6379
6368
|
return;
|
|
@@ -6392,13 +6381,13 @@ class Chain extends VersionControl {
|
|
|
6392
6381
|
debug(`[consensus] Cannot fetch proposed block ${blockHash}:`, e?.message);
|
|
6393
6382
|
return;
|
|
6394
6383
|
}
|
|
6395
|
-
this.#consensusRound = round;
|
|
6384
|
+
this.#consensusRound = Number(round);
|
|
6396
6385
|
if (this.#roundTimer) {
|
|
6397
6386
|
clearTimeout(this.#roundTimer);
|
|
6398
6387
|
this.#roundTimer = null;
|
|
6399
6388
|
}
|
|
6400
6389
|
if (validators.includes(peernet.selectedAccount) && !this.#isJailed(peernet.selectedAccount)) {
|
|
6401
|
-
await this.#castVote('prevote', blockHash, index, round);
|
|
6390
|
+
await this.#castVote('prevote', blockHash, Number(index), Number(round));
|
|
6402
6391
|
}
|
|
6403
6392
|
}
|
|
6404
6393
|
catch (e) {
|
|
@@ -6411,13 +6400,14 @@ class Chain extends VersionControl {
|
|
|
6411
6400
|
*/
|
|
6412
6401
|
this.#handlePrevote = async (payload) => {
|
|
6413
6402
|
try {
|
|
6414
|
-
const
|
|
6403
|
+
const message = new PrevoteMessage(payload);
|
|
6404
|
+
const msg = message.decoded;
|
|
6415
6405
|
const { blockHash, index, round, from } = msg;
|
|
6416
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6406
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6417
6407
|
if (!validators.includes(from))
|
|
6418
6408
|
return;
|
|
6419
6409
|
const localBlock = await this.lastBlock;
|
|
6420
|
-
const localIndex = localBlock?.index !== undefined ?
|
|
6410
|
+
const localIndex = localBlock?.index !== undefined ? localBlock.index : -1n;
|
|
6421
6411
|
if (index <= localIndex)
|
|
6422
6412
|
return;
|
|
6423
6413
|
const voteKey = `${index}:${round}:${blockHash}`;
|
|
@@ -6430,7 +6420,7 @@ class Chain extends VersionControl {
|
|
|
6430
6420
|
if (voteCount >= threshold &&
|
|
6431
6421
|
validators.includes(peernet.selectedAccount) &&
|
|
6432
6422
|
!this.#isJailed(peernet.selectedAccount)) {
|
|
6433
|
-
await this.#castVote('precommit', blockHash, index, round);
|
|
6423
|
+
await this.#castVote('precommit', blockHash, Number(index), Number(round));
|
|
6434
6424
|
}
|
|
6435
6425
|
}
|
|
6436
6426
|
catch (e) {
|
|
@@ -6444,12 +6434,13 @@ class Chain extends VersionControl {
|
|
|
6444
6434
|
*/
|
|
6445
6435
|
this.#handlePrecommit = async (payload) => {
|
|
6446
6436
|
try {
|
|
6447
|
-
const
|
|
6437
|
+
const message = new PrecommitMessage(payload);
|
|
6438
|
+
const msg = message.decoded;
|
|
6448
6439
|
const { blockHash, index, round, from } = msg;
|
|
6449
|
-
const validators = await this.#getConsensusValidators(index);
|
|
6440
|
+
const validators = await this.#getConsensusValidators(Number(index));
|
|
6450
6441
|
if (!validators.includes(from))
|
|
6451
6442
|
return;
|
|
6452
|
-
if (index <= this.#committedHeight)
|
|
6443
|
+
if (index <= BigInt(this.#committedHeight))
|
|
6453
6444
|
return;
|
|
6454
6445
|
const voteKey = `${index}:${round}:${blockHash}`;
|
|
6455
6446
|
if (!this.#precommits.has(voteKey))
|
|
@@ -6458,27 +6449,27 @@ class Chain extends VersionControl {
|
|
|
6458
6449
|
const threshold = Math.ceil((2 * validators.length) / 3);
|
|
6459
6450
|
const voteCount = this.#precommits.get(voteKey).size;
|
|
6460
6451
|
debug(`[consensus] Precommits ${voteKey}: ${voteCount}/${validators.length} (need ${threshold})`);
|
|
6461
|
-
if (voteCount >= threshold && index > this.#committedHeight) {
|
|
6462
|
-
this.#committedHeight = index;
|
|
6452
|
+
if (voteCount >= threshold && index > BigInt(this.#committedHeight)) {
|
|
6453
|
+
this.#committedHeight = Number(index);
|
|
6463
6454
|
this.#consensusRound = 0;
|
|
6464
6455
|
// Prune vote state for committed and older heights
|
|
6465
6456
|
for (const key of [...this.#prevotes.keys()]) {
|
|
6466
|
-
if (
|
|
6457
|
+
if (BigInt(key.split(':')[0]) <= index)
|
|
6467
6458
|
this.#prevotes.delete(key);
|
|
6468
6459
|
}
|
|
6469
6460
|
for (const key of [...this.#precommits.keys()]) {
|
|
6470
|
-
if (
|
|
6461
|
+
if (BigInt(key.split(':')[0]) <= index)
|
|
6471
6462
|
this.#precommits.delete(key);
|
|
6472
6463
|
}
|
|
6473
6464
|
for (const key of [...this.#castedVotes]) {
|
|
6474
|
-
if (
|
|
6465
|
+
if (BigInt(key.split(':')[1]) <= index)
|
|
6475
6466
|
this.#castedVotes.delete(key);
|
|
6476
6467
|
}
|
|
6477
6468
|
// Non-proposers add the block to local state now.
|
|
6478
6469
|
// Proposers already committed state in #createBlock() and their
|
|
6479
6470
|
// lastBlock.index === index, so the guard below skips them.
|
|
6480
6471
|
const currentBlock = await this.lastBlock;
|
|
6481
|
-
const currentIndex = currentBlock?.index !== undefined ?
|
|
6472
|
+
const currentIndex = currentBlock?.index !== undefined ? currentBlock.index : -1n;
|
|
6482
6473
|
if (index > currentIndex) {
|
|
6483
6474
|
debug(`[consensus] ✅ Committing block ${blockHash} at height ${index}`);
|
|
6484
6475
|
try {
|
|
@@ -6751,7 +6742,9 @@ class Chain extends VersionControl {
|
|
|
6751
6742
|
await globalThis.peernet.addRequestHandler('transactionPool', this.#transactionPoolHandler.bind(this));
|
|
6752
6743
|
await globalThis.peernet.addRequestHandler('version', this.#versionHandler.bind(this));
|
|
6753
6744
|
await globalThis.peernet.addRequestHandler('stateInfo', () => {
|
|
6754
|
-
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
|
+
});
|
|
6755
6748
|
});
|
|
6756
6749
|
globalThis.peernet.subscribe('add-block', this.#addBlock.bind(this));
|
|
6757
6750
|
globalThis.peernet.subscribe('invalid-transaction', this.#invalidTransaction.bind(this));
|
|
@@ -6839,13 +6832,8 @@ class Chain extends VersionControl {
|
|
|
6839
6832
|
async getPeerTransactionPool(peer) {
|
|
6840
6833
|
let transactionsInPool = await this.#makeRequest(peer, 'transactionPool');
|
|
6841
6834
|
if (transactionsInPool instanceof Uint8Array) {
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
transactionsInPool = JSON.parse(text);
|
|
6845
|
-
}
|
|
6846
|
-
catch (e) {
|
|
6847
|
-
return [];
|
|
6848
|
-
}
|
|
6835
|
+
debug('transactionPool response must be decoded array payload');
|
|
6836
|
+
return [];
|
|
6849
6837
|
}
|
|
6850
6838
|
if (!Array.isArray(transactionsInPool))
|
|
6851
6839
|
return [];
|
|
@@ -6877,13 +6865,7 @@ class Chain extends VersionControl {
|
|
|
6877
6865
|
try {
|
|
6878
6866
|
let versionResponse = await this.#makeRequest(peer, 'version');
|
|
6879
6867
|
if (versionResponse instanceof Uint8Array) {
|
|
6880
|
-
|
|
6881
|
-
try {
|
|
6882
|
-
versionResponse = JSON.parse(decoded);
|
|
6883
|
-
}
|
|
6884
|
-
catch {
|
|
6885
|
-
versionResponse = decoded;
|
|
6886
|
-
}
|
|
6868
|
+
versionResponse = new TextDecoder().decode(versionResponse);
|
|
6887
6869
|
}
|
|
6888
6870
|
if (typeof versionResponse === 'string') {
|
|
6889
6871
|
peer.version = versionResponse;
|
|
@@ -6893,6 +6875,12 @@ class Chain extends VersionControl {
|
|
|
6893
6875
|
typeof versionResponse.version === 'string') {
|
|
6894
6876
|
peer.version = versionResponse.version;
|
|
6895
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
|
+
}
|
|
6896
6884
|
}
|
|
6897
6885
|
catch (error) {
|
|
6898
6886
|
debug(`failed to request version from peer ${peerId}:`, error?.message ?? error);
|
|
@@ -6901,7 +6889,9 @@ class Chain extends VersionControl {
|
|
|
6901
6889
|
}
|
|
6902
6890
|
debug(`peer connected with version ${peer.version}`);
|
|
6903
6891
|
if (!this.isVersionCompatible(peer.version)) {
|
|
6904
|
-
|
|
6892
|
+
const mismatchReason = `incompatible peer version ${peer.version} (local: ${this.version})`;
|
|
6893
|
+
console.error(`[chain] ${mismatchReason}`);
|
|
6894
|
+
await this.#recordPeerFailure(peerId, mismatchReason);
|
|
6905
6895
|
return;
|
|
6906
6896
|
}
|
|
6907
6897
|
let lastBlock;
|
|
@@ -6921,7 +6911,7 @@ class Chain extends VersionControl {
|
|
|
6921
6911
|
// This prevents Byzantine nodes from claiming a fake chain length to steer our sync
|
|
6922
6912
|
const localBlock = await this.lastBlock;
|
|
6923
6913
|
const MAX_SYNC_AHEAD = 100_000;
|
|
6924
|
-
if (lastBlock?.index > (localBlock?.index ?? 0) + MAX_SYNC_AHEAD) {
|
|
6914
|
+
if (lastBlock?.index > BigInt(localBlock?.index ?? 0) + BigInt(MAX_SYNC_AHEAD)) {
|
|
6925
6915
|
const peerName = peer?.peerId || peer?.id || peer?.address || peerId || 'unknown';
|
|
6926
6916
|
debug(`Peer ${peerName} claims unreasonable block height ${lastBlock.index} (local: ${localBlock?.index ?? 0})`);
|
|
6927
6917
|
await this.#recordPeerFailure(peerId, `unreasonable lastBlock index: ${lastBlock.index}`);
|
|
@@ -6937,15 +6927,13 @@ class Chain extends VersionControl {
|
|
|
6937
6927
|
try {
|
|
6938
6928
|
let knownBlocksResponse = await this.#makeRequest(peer, 'knownBlocks');
|
|
6939
6929
|
if (knownBlocksResponse instanceof Uint8Array) {
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
console.log(e);
|
|
6945
|
-
}
|
|
6930
|
+
const reason = `knownBlocks must be object response, got raw bytes from ${peerId}`;
|
|
6931
|
+
debug(reason);
|
|
6932
|
+
await this.#recordPeerFailure(peerId, reason);
|
|
6933
|
+
return;
|
|
6946
6934
|
}
|
|
6947
6935
|
const MAX_WANTLIST_SIZE = 1000;
|
|
6948
|
-
if (knownBlocksResponse.blocks) {
|
|
6936
|
+
if (knownBlocksResponse && Array.isArray(knownBlocksResponse.blocks)) {
|
|
6949
6937
|
const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
|
|
6950
6938
|
if (remaining > 0) {
|
|
6951
6939
|
for (const hash of knownBlocksResponse.blocks.slice(0, remaining)) {
|
|
@@ -6987,12 +6975,7 @@ class Chain extends VersionControl {
|
|
|
6987
6975
|
try {
|
|
6988
6976
|
let stateInfo = await this.#makeRequest(peer, 'stateInfo');
|
|
6989
6977
|
if (stateInfo instanceof Uint8Array) {
|
|
6990
|
-
|
|
6991
|
-
stateInfo = JSON.parse(new TextDecoder().decode(stateInfo));
|
|
6992
|
-
}
|
|
6993
|
-
catch (e) {
|
|
6994
|
-
console.log(e);
|
|
6995
|
-
}
|
|
6978
|
+
stateInfo = new StateMessage(stateInfo).decoded;
|
|
6996
6979
|
}
|
|
6997
6980
|
await this.syncChain(lastBlock);
|
|
6998
6981
|
this.machine.states.info = stateInfo;
|
|
@@ -7010,7 +6993,7 @@ class Chain extends VersionControl {
|
|
|
7010
6993
|
return new globalThis.peernet.protos['peernet-response']({ response: pool });
|
|
7011
6994
|
}
|
|
7012
6995
|
async #versionHandler() {
|
|
7013
|
-
return new globalThis.peernet.protos['peernet-response']({ response:
|
|
6996
|
+
return new globalThis.peernet.protos['peernet-response']({ response: this.version });
|
|
7014
6997
|
}
|
|
7015
6998
|
async #executeTransaction({ hash, from, to, method, params, nonce }) {
|
|
7016
6999
|
try {
|
|
@@ -7362,12 +7345,14 @@ class Chain extends VersionControl {
|
|
|
7362
7345
|
debug(`created block: ${hash} @${block.index}`);
|
|
7363
7346
|
// Phase 2: announce proposal for consensus voting instead of direct add-block
|
|
7364
7347
|
console.log(`[consensus] 📤 Proposing block #${block.index} | hash: ${hash} | round: ${this.#consensusRound}`);
|
|
7365
|
-
const
|
|
7348
|
+
const proposalData = {
|
|
7366
7349
|
blockHash: hash,
|
|
7367
|
-
index: block.index,
|
|
7368
|
-
round: this.#consensusRound,
|
|
7350
|
+
index: BigInt(block.index),
|
|
7351
|
+
round: BigInt(this.#consensusRound),
|
|
7369
7352
|
from: peernet.selectedAccount
|
|
7370
|
-
}
|
|
7353
|
+
};
|
|
7354
|
+
const proposalMessage = new ProposalMessage(proposalData);
|
|
7355
|
+
const proposalPayload = proposalMessage.encoded;
|
|
7371
7356
|
try {
|
|
7372
7357
|
globalThis.peernet.publish('consensus:propose', proposalPayload);
|
|
7373
7358
|
}
|