@leofcoin/chain 1.10.18 → 1.10.19

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.
@@ -1,4 +1,4 @@
1
- import { s as signTransaction, c as MultiWallet, d as createTransactionHash } from './index-DmuI-29u.js';
1
+ import { s as signTransaction, c as MultiWallet, d as createTransactionHash } from './index-DCbLvMKL.js';
2
2
  import { f as fromBase58 } from './index-CvKt4UDE.js';
3
3
  import './browser-crypto-CH0ua22L.js';
4
4
  import './sha2-BKcEJzgd.js';
@@ -1,6 +1,6 @@
1
1
  import { F as FormatInterface, p as proto, a as proto$1, b as proto$2, T as TransactionMessage, j as jsonStringifyBigInt, c as jsonParseBigInt, C as ContractMessage, d as Codec } from './browser-crypto-CH0ua22L.js';
2
2
  import { B as BlockMessage, L as LastBlockMessage, P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO, C as ConnectionMonitor, a as BWMessage, S as StateMessage } from './connection-monitor-D-krNiRH.js';
3
- import { M as MAX_TRANSACTION_BYTES, a as MAX_BLOCK_TRANSACTION_BYTES, b as MAX_BLOCK_TRANSACTIONS, c as MultiWallet, d as createTransactionHash, e as calculateFee, f as createContractMessage, s as signTransaction, r as randombytes, g as distributeTransactionFee, h as supportsTransactionFees, i as supportsMonetaryPolicy, v as validateBlockResourceLimits, j as calculateMonetaryPolicy, k as distributeAmount, l as aggregateValidatorFees, m as MONETARY_POLICY_AUTHORITY, n as contractFactoryMessage, o as nativeTokenMessage, p as validatorsMessage, q as nameServiceMessage, t as parseUnits, u as formatUnits } from './index-DmuI-29u.js';
3
+ import { M as MAX_TRANSACTION_BYTES, a as MAX_BLOCK_TRANSACTION_BYTES, b as MAX_BLOCK_TRANSACTIONS, c as MultiWallet, d as createTransactionHash, e as calculateFee, f as createContractMessage, s as signTransaction, r as randombytes, g as distributeTransactionFee, h as supportsTransactionFees, i as supportsMonetaryPolicy, v as validateBlockResourceLimits, j as calculateMonetaryPolicy, k as distributeAmount, l as aggregateValidatorFees, m as MONETARY_POLICY_AUTHORITY, n as contractFactoryMessage, o as nativeTokenMessage, p as validatorsMessage, q as nameServiceMessage, t as parseUnits, u as formatUnits } from './index-DCbLvMKL.js';
4
4
  import { f as fromBase58 } from './index-CvKt4UDE.js';
5
5
  import { g as getDefaultExportFromCjs } from './_commonjsHelpers-B85MJLTf.js';
6
6
  import { q as quorumThreshold } from './quorum-S_qdgiAY.js';
@@ -3233,7 +3233,8 @@ class ContractRegistry {
3233
3233
  */
3234
3234
  async registerNameInNameService(name, hash, chain, signer) {
3235
3235
  ({
3236
- from: await signer.address});
3236
+ from: await signer.address,
3237
+ to: addresses.nameService});
3237
3238
  }
3238
3239
  /**
3239
3240
  * Get a base contract by name
@@ -5260,6 +5261,73 @@ const assertHashFormatState = async (chainStore, stateStore) => {
5260
5261
  }
5261
5262
  };
5262
5263
 
5264
+ const CHAIN_ID_SCHEMA = "leofcoin:chain-identity:v1";
5265
+ const GENESIS_CONTRACT_NAMES = ["contractFactory", "nativeToken", "nameService", "validators"];
5266
+ const assertChainId = (value) => {
5267
+ if (typeof value !== "string" || !/^lfc:[0-9a-f]{64}$/.test(value))
5268
+ throw new Error("Invalid chain ID; expected lfc: followed by 64 lowercase hex characters");
5269
+ return value;
5270
+ };
5271
+ const createChainIdentity = async (network, contracts) => {
5272
+ if (typeof network !== "string" || !/^[a-z0-9][a-z0-9:-]{0,79}$/.test(network))
5273
+ throw new Error("Invalid genesis network namespace");
5274
+ const genesisContracts = {};
5275
+ for (const name of GENESIS_CONTRACT_NAMES) {
5276
+ const hash = contracts?.[name];
5277
+ if (typeof hash !== "string" || !/^[A-Z2-7]{32,128}$/.test(hash))
5278
+ throw new Error(`Invalid genesis contract hash: ${name}`);
5279
+ genesisContracts[name] = hash;
5280
+ }
5281
+ const bytes = new TextEncoder().encode(JSON.stringify({ schema: CHAIN_ID_SCHEMA, network, genesisContracts }));
5282
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
5283
+ const chainId = "lfc:" + [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
5284
+ return { schema: CHAIN_ID_SCHEMA, chainId, network, genesisContracts };
5285
+ };
5286
+ const verifyChainIdentity = async (value) => {
5287
+ const identity = value;
5288
+ if (!identity || identity.schema !== CHAIN_ID_SCHEMA)
5289
+ throw new Error("Unsupported chain identity response");
5290
+ const verified = await createChainIdentity(identity.network, identity.genesisContracts);
5291
+ if (verified.chainId !== assertChainId(identity.chainId))
5292
+ throw new Error("Chain ID does not match its genesis contracts");
5293
+ return verified;
5294
+ };
5295
+ const findChainPresence = async (chainId, peerIds, requestIdentity, timeoutMs = 3e3) => {
5296
+ assertChainId(chainId);
5297
+ const peers = [...new Set(peerIds)].slice(0, 16);
5298
+ const matches = [];
5299
+ let responded = 0;
5300
+ let unavailable = 0;
5301
+ await Promise.all(peers.map(async (peerId) => {
5302
+ let timer;
5303
+ try {
5304
+ const result = await Promise.race([
5305
+ Promise.resolve().then(() => requestIdentity(peerId)),
5306
+ new Promise((_, reject) => {
5307
+ timer = setTimeout(() => reject(new Error("Chain identity request timed out")), timeoutMs);
5308
+ })
5309
+ ]);
5310
+ const identity = await verifyChainIdentity(result);
5311
+ responded++;
5312
+ if (identity.chainId === chainId)
5313
+ matches.push(peerId);
5314
+ } catch {
5315
+ unavailable++;
5316
+ } finally {
5317
+ clearTimeout(timer);
5318
+ }
5319
+ }));
5320
+ return {
5321
+ chainId,
5322
+ status: matches.length ? "found" : !peers.length || unavailable ? "unknown" : "not-observed",
5323
+ checkedPeers: peers.length,
5324
+ respondedPeers: responded,
5325
+ unavailablePeers: unavailable,
5326
+ matchingPeers: matches.sort(),
5327
+ scope: "reachable peers only; offline or undiscovered chains may still exist"
5328
+ };
5329
+ };
5330
+
5263
5331
  const debug = createDebugger("leofcoin/chain");
5264
5332
  class Chain extends VersionControl {
5265
5333
  constructor(config) {
@@ -5527,6 +5595,32 @@ class Chain extends VersionControl {
5527
5595
  get nativeToken() {
5528
5596
  return addresses.nativeToken;
5529
5597
  }
5598
+ /** Immutable bundled genesis identity, independent of the current chain tip. */
5599
+ getChainIdentity() {
5600
+ return createChainIdentity(globalThis.peernet?.network || "leofcoin:peach", addresses);
5601
+ }
5602
+ async findChain(chainId) {
5603
+ assertChainId(chainId);
5604
+ const local = await this.getChainIdentity();
5605
+ if (local.chainId === chainId) return {
5606
+ chainId,
5607
+ status: "found",
5608
+ foundViaLocalNode: true,
5609
+ checkedPeers: 0,
5610
+ respondedPeers: 0,
5611
+ unavailablePeers: 0,
5612
+ matchingPeers: [],
5613
+ scope: "local node; not proof of a globally available or finalized chain"
5614
+ };
5615
+ const peers = Object.entries(globalThis.peernet?.connections || {}).filter(([, peer]) => peer.connected && typeof peer.request === "function");
5616
+ return {
5617
+ ...await findChainPresence(chainId, peers.map(([id]) => id), async (id) => {
5618
+ const peer = peers.find(([peerId]) => peerId === id)?.[1];
5619
+ return this.#makeRequest(peer, "chainIdentity");
5620
+ }),
5621
+ foundViaLocalNode: false
5622
+ };
5623
+ }
5530
5624
  get validators() {
5531
5625
  return [...this.#validators];
5532
5626
  }
@@ -5821,6 +5915,10 @@ class Chain extends VersionControl {
5821
5915
  });
5822
5916
  await globalThis.peernet.addRequestHandler("transactionPool", this.#transactionPoolHandler.bind(this));
5823
5917
  await globalThis.peernet.addRequestHandler("version", this.#versionHandler.bind(this));
5918
+ await globalThis.peernet.addRequestHandler(
5919
+ "chainIdentity",
5920
+ async () => new globalThis.peernet.protos["peernet-response"]({ response: await this.getChainIdentity() })
5921
+ );
5824
5922
  await globalThis.peernet.addRequestHandler("stateInfo", async () => {
5825
5923
  const lastblock = await this.lastBlock || { index: 0, hash: "0x0", previousHash: "0x0" };
5826
5924
  const values = this.machine?.states?.info || {};
@@ -959,6 +959,7 @@ var bytecodes = {
959
959
  nameService,
960
960
  validators
961
961
  };
962
+
962
963
  const contractFactoryMessage = bytecodes.contractFactory;
963
964
  const nativeTokenMessage = bytecodes.nativeToken;
964
965
  const nameServiceMessage = bytecodes.nameService;
package/exports/chain.js CHANGED
@@ -14,6 +14,7 @@ import { P as PROTOCOL_VERSION, R as REACHED_ONE_ZERO_ZERO } from './constants-D
14
14
  import ConnectionMonitor from './connection-monitor.js';
15
15
  import { q as quorumThreshold } from './quorum-S_qdgiAY.js';
16
16
  import { assertHashFormatState } from './hash-format-state.js';
17
+ import { createChainIdentity, assertChainId, findChainPresence } from '@leofcoin/lib/chain-identity';
17
18
  import '@leofcoin/networks';
18
19
 
19
20
  const limit = 1800;
@@ -2477,6 +2478,32 @@ class Chain extends VersionControl {
2477
2478
  get nativeToken() {
2478
2479
  return addresses.nativeToken;
2479
2480
  }
2481
+ /** Immutable bundled genesis identity, independent of the current chain tip. */
2482
+ getChainIdentity() {
2483
+ return createChainIdentity(globalThis.peernet?.network || "leofcoin:peach", addresses);
2484
+ }
2485
+ async findChain(chainId) {
2486
+ assertChainId(chainId);
2487
+ const local = await this.getChainIdentity();
2488
+ if (local.chainId === chainId) return {
2489
+ chainId,
2490
+ status: "found",
2491
+ foundViaLocalNode: true,
2492
+ checkedPeers: 0,
2493
+ respondedPeers: 0,
2494
+ unavailablePeers: 0,
2495
+ matchingPeers: [],
2496
+ scope: "local node; not proof of a globally available or finalized chain"
2497
+ };
2498
+ const peers = Object.entries(globalThis.peernet?.connections || {}).filter(([, peer]) => peer.connected && typeof peer.request === "function");
2499
+ return {
2500
+ ...await findChainPresence(chainId, peers.map(([id]) => id), async (id) => {
2501
+ const peer = peers.find(([peerId]) => peerId === id)?.[1];
2502
+ return this.#makeRequest(peer, "chainIdentity");
2503
+ }),
2504
+ foundViaLocalNode: false
2505
+ };
2506
+ }
2480
2507
  get validators() {
2481
2508
  return [...this.#validators];
2482
2509
  }
@@ -2771,6 +2798,10 @@ class Chain extends VersionControl {
2771
2798
  });
2772
2799
  await globalThis.peernet.addRequestHandler("transactionPool", this.#transactionPoolHandler.bind(this));
2773
2800
  await globalThis.peernet.addRequestHandler("version", this.#versionHandler.bind(this));
2801
+ await globalThis.peernet.addRequestHandler(
2802
+ "chainIdentity",
2803
+ async () => new globalThis.peernet.protos["peernet-response"]({ response: await this.getChainIdentity() })
2804
+ );
2774
2805
  await globalThis.peernet.addRequestHandler("stateInfo", async () => {
2775
2806
  const lastblock = await this.lastBlock || { index: 0, hash: "0x0", previousHash: "0x0" };
2776
2807
  const values = this.machine?.states?.info || {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leofcoin/chain",
3
- "version": "1.10.18",
3
+ "version": "1.10.19",
4
4
  "description": "Official javascript implementation",
5
5
  "private": false,
6
6
  "exports": {