@hardkas/localnet 0.5.5-alpha → 0.6.1-alpha

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.
@@ -3,8 +3,9 @@ import fs from "fs/promises";
3
3
  import path from "path";
4
4
  import { existsSync } from "fs";
5
5
  import { writeFileAtomic } from "@hardkas/core";
6
+ import { deterministicCompare } from "@hardkas/core";
6
7
  function getDefaultTracesDir(cwd = process.cwd()) {
7
- return path.join(cwd, ".hardkas", "traces");
8
+ return path.join(cwd, ".hardkas", "artifacts");
8
9
  }
9
10
  function getTracePath(txId, cwd) {
10
11
  validateTxId(txId);
@@ -49,7 +50,7 @@ async function listSimulatedTraces(options) {
49
50
  }
50
51
  }
51
52
  }
52
- return traces.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
53
+ return traces.sort((a, b) => deterministicCompare(b.createdAt, a.createdAt));
53
54
  }
54
55
 
55
56
  export {
@@ -3,8 +3,9 @@ import fs from "fs/promises";
3
3
  import path from "path";
4
4
  import { existsSync } from "fs";
5
5
  import { writeFileAtomic } from "@hardkas/core";
6
+ import { deterministicCompare } from "@hardkas/core";
6
7
  function getDefaultReceiptsDir(cwd = process.cwd()) {
7
- return path.join(cwd, ".hardkas", "receipts");
8
+ return path.join(cwd, ".hardkas", "artifacts");
8
9
  }
9
10
  function getReceiptPath(txId, cwd) {
10
11
  validateTxId(txId);
@@ -49,7 +50,7 @@ async function listSimulatedReceipts(options) {
49
50
  }
50
51
  }
51
52
  }
52
- return receipts.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
53
+ return receipts.sort((a, b) => deterministicCompare(b.createdAt, a.createdAt));
53
54
  }
54
55
 
55
56
  export {
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import * as _hardkas_artifacts from '@hardkas/artifacts';
2
- import { HardkasArtifactBase, Snapshot as Snapshot$1, ARTIFACT_SCHEMAS, TxReceipt, TxPlan } from '@hardkas/artifacts';
2
+ import { HardkasArtifactBase, Snapshot as Snapshot$1, TxPlan, ARTIFACT_SCHEMAS, TxReceipt } from '@hardkas/artifacts';
3
3
  import * as _hardkas_simulator from '@hardkas/simulator';
4
- import { ExecutionMode, NetworkId } from '@hardkas/core';
4
+ import { ExecutionMode, NetworkId, RuntimeContext } from '@hardkas/core';
5
5
  import { KaspaRpcClient } from '@hardkas/kaspa-rpc';
6
6
 
7
7
  interface HardkasAccount {
8
8
  readonly name: string;
9
9
  readonly address: string;
10
+ readonly evmAddress: string;
10
11
  readonly balanceSompi: bigint;
11
12
  }
12
13
  declare function createDeterministicAccounts(input?: {
@@ -175,6 +176,15 @@ interface CreateInitialStateOptions {
175
176
  }
176
177
  declare function createInitialLocalnetState(options?: CreateInitialStateOptions): LocalnetState;
177
178
  declare function resolveAccountAddressFromState(state: LocalnetState, nameOrAddress: string): string;
179
+ /**
180
+ * Mathematically reconstructs the deterministc localnet state at a specific past DAA score.
181
+ * Annoys UTXOs created after the target DAA and revives UTXOs spent after the target DAA.
182
+ *
183
+ * @param state The current localnet state
184
+ * @param targetDaa The block DAG score to revert to
185
+ * @returns A new immutable localnet state representing the exact state at the target DAA
186
+ */
187
+ declare function reconstructStateAtDaa(state: LocalnetState, targetDaa: bigint | string): LocalnetState;
178
188
 
179
189
  declare function getDefaultLocalnetDir(cwd?: string): string;
180
190
  declare function getDefaultLocalnetStatePath(cwd?: string): string;
@@ -220,7 +230,7 @@ declare function createLocalnetSnapshot(state: LocalnetState, name?: string): Lo
220
230
  /**
221
231
  * Verifies the integrity of a snapshot.
222
232
  */
223
- declare function verifySnapshot(snapshot: any): SnapshotVerificationResult;
233
+ declare function verifySnapshot(snapshot: Snapshot$1): SnapshotVerificationResult;
224
234
  /**
225
235
  * Restores a snapshot with atomic safety and verification.
226
236
  */
@@ -239,12 +249,11 @@ declare const DUST_LIMIT_SOMPI = 600n;
239
249
  /**
240
250
  * Applies a simulated payment to the localnet state with atomic safety and validation.
241
251
  */
242
- declare function applySimulatedPayment(state: LocalnetState, input: SimulatedPaymentInput): SimulationResult;
252
+ declare function applySimulatedPayment(state: LocalnetState, input: SimulatedPaymentInput, ctx: RuntimeContext): SimulationResult;
243
253
  /**
244
254
  * Executes a pre-built transaction plan against the simulated state.
245
255
  */
246
- declare function applySimulatedPlan(state: LocalnetState, planArtifact: any, // TxPlanArtifact
247
- options?: {
256
+ declare function applySimulatedPlan(state: LocalnetState, planArtifact: TxPlan, ctx: RuntimeContext, options?: {
248
257
  txId?: string;
249
258
  }): SimulationResult;
250
259
 
@@ -338,7 +347,7 @@ interface SimulatedReplaySummary {
338
347
  * Implements an honest replay model that differentiates between
339
348
  * reproduced results and unimplemented consensus/bridge features.
340
349
  */
341
- declare function verifyReplay(state: LocalnetState, originalPlan: TxPlan, originalReceipt: TxReceipt): ReplayVerificationReport;
350
+ declare function verifyReplay(state: LocalnetState, originalPlan: TxPlan, originalReceipt: TxReceipt, ctx: RuntimeContext): ReplayVerificationReport;
342
351
  /**
343
352
  * Loads receipt and trace for a transaction and produces a summary.
344
353
  */
@@ -404,4 +413,4 @@ interface ForkOptions {
404
413
  }
405
414
  declare function forkFromNetwork(rpc: KaspaRpcClient, opts: ForkOptions): Promise<LocalnetState>;
406
415
 
407
- export { type CreateInitialStateOptions, DUST_LIMIT_SOMPI, type ForkOptions, type FundAddressInput, type HardkasAccount, type HardkasDevnet, type LocalnetAccount, type LocalnetState, type LocalnetUtxo, type ReplayInvariantResult, type ReplayVerificationReport, type SimulatedBlock, type SimulatedDag, SimulatedKaspaChain, type SimulatedPaymentInput, type SimulatedReplaySummary, type SimulatedUtxo, type SimulationResult, type Snapshot, type SnapshotRestoreResult, type SnapshotVerificationResult, type StateTransition, type StoredSimulatedTxReceipt, type StoredSimulatedTxTrace, type StoredTraceEvent, addSimulatedBlock, applySimulatedPayment, applySimulatedPlan, calculateAccountsHash, calculateStateHash, calculateUtxoSetHash, createDeterministicAccounts, createInitialLocalnetState, createLocalnetSnapshot, createSimulatedDag, findBestTip, forkFromNetwork, fundAddress, getAccountBalanceSompi, getAddressBalanceSompi, getDagColoring, getDefaultLocalnetDir, getDefaultLocalnetStatePath, getDefaultReceiptsDir, getDefaultTracesDir, getReceiptPath, getSelectedChain, getSimulatedReplaySummary, getSpendableUtxos, getTracePath, listSimulatedReceipts, listSimulatedTraces, loadLocalnetState, loadOrCreateLocalnetState, loadSimulatedReceipt, loadSimulatedTrace, moveSink, resetLocalnetState, resolveAccountAddress, resolveAccountAddressFromState, resolveConflictsDeterministically, restoreLocalnetSnapshot, saveLocalnetState, saveSimulatedReceipt, saveSimulatedTrace, startSimulatedDevnet, verifyReplay, verifySnapshot };
416
+ export { type CreateInitialStateOptions, DUST_LIMIT_SOMPI, type ForkOptions, type FundAddressInput, type HardkasAccount, type HardkasDevnet, type LocalnetAccount, type LocalnetState, type LocalnetUtxo, type ReplayInvariantResult, type ReplayVerificationReport, type SimulatedBlock, type SimulatedDag, SimulatedKaspaChain, type SimulatedPaymentInput, type SimulatedReplaySummary, type SimulatedUtxo, type SimulationResult, type Snapshot, type SnapshotRestoreResult, type SnapshotVerificationResult, type StateTransition, type StoredSimulatedTxReceipt, type StoredSimulatedTxTrace, type StoredTraceEvent, addSimulatedBlock, applySimulatedPayment, applySimulatedPlan, calculateAccountsHash, calculateStateHash, calculateUtxoSetHash, createDeterministicAccounts, createInitialLocalnetState, createLocalnetSnapshot, createSimulatedDag, findBestTip, forkFromNetwork, fundAddress, getAccountBalanceSompi, getAddressBalanceSompi, getDagColoring, getDefaultLocalnetDir, getDefaultLocalnetStatePath, getDefaultReceiptsDir, getDefaultTracesDir, getReceiptPath, getSelectedChain, getSimulatedReplaySummary, getSpendableUtxos, getTracePath, listSimulatedReceipts, listSimulatedTraces, loadLocalnetState, loadOrCreateLocalnetState, loadSimulatedReceipt, loadSimulatedTrace, moveSink, reconstructStateAtDaa, resetLocalnetState, resolveAccountAddress, resolveAccountAddressFromState, resolveConflictsDeterministically, restoreLocalnetSnapshot, saveLocalnetState, saveSimulatedReceipt, saveSimulatedTrace, startSimulatedDevnet, verifyReplay, verifySnapshot };
package/dist/index.js CHANGED
@@ -4,16 +4,28 @@ import {
4
4
  listSimulatedReceipts,
5
5
  loadSimulatedReceipt,
6
6
  saveSimulatedReceipt
7
- } from "./chunk-GVBX3TPM.js";
7
+ } from "./chunk-M5T6T465.js";
8
8
  import {
9
9
  getDefaultTracesDir,
10
10
  getTracePath,
11
11
  listSimulatedTraces,
12
12
  loadSimulatedTrace,
13
13
  saveSimulatedTrace
14
- } from "./chunk-DPHHOGGK.js";
14
+ } from "./chunk-6AICYLVR.js";
15
15
 
16
16
  // src/accounts.ts
17
+ var DEFAULT_EVM_ADDRESSES = [
18
+ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
19
+ // alice
20
+ "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
21
+ // bob
22
+ "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
23
+ // carol
24
+ "0x90F79bf6EB2c4f870365E785982E1f101E93b906",
25
+ // dave
26
+ "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65"
27
+ // erin
28
+ ];
17
29
  function createDeterministicAccounts(input) {
18
30
  const count = input?.count ?? 5;
19
31
  const initialBalanceSompi = input?.initialBalanceSompi ?? 1000n * 100000000n;
@@ -23,6 +35,7 @@ function createDeterministicAccounts(input) {
23
35
  return {
24
36
  name,
25
37
  address: `kaspa:sim_${name}`,
38
+ evmAddress: DEFAULT_EVM_ADDRESSES[index] || `0x000000000000000000000000000000000000000${index}`,
26
39
  balanceSompi: initialBalanceSompi
27
40
  };
28
41
  });
@@ -135,6 +148,7 @@ function createInitialLocalnetState(options = {}) {
135
148
  hardkasVersion: HARDKAS_VERSION,
136
149
  version: "1.0.0-alpha",
137
150
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
151
+ // hardkas-determinism-allow: initial state creation timestamp
138
152
  mode: "simulated",
139
153
  networkId: "simnet",
140
154
  daaScore: "0",
@@ -162,6 +176,21 @@ function resolveAccountAddressFromState(state, nameOrAddress) {
162
176
  }
163
177
  return nameOrAddress;
164
178
  }
179
+ function reconstructStateAtDaa(state, targetDaa) {
180
+ const target = typeof targetDaa === "string" ? BigInt(targetDaa) : targetDaa;
181
+ const reconstructedUtxos = state.utxos.filter((u) => BigInt(u.createdAtDaaScore || "0") <= target).map((u) => {
182
+ if (u.spent && u.spentAtDaaScore && BigInt(u.spentAtDaaScore) > target) {
183
+ const { spentAtDaaScore: _, ...rest } = u;
184
+ return { ...rest, spent: false };
185
+ }
186
+ return u;
187
+ });
188
+ return {
189
+ ...state,
190
+ daaScore: target.toString(),
191
+ utxos: reconstructedUtxos
192
+ };
193
+ }
165
194
 
166
195
  // src/store.ts
167
196
  import fs from "fs/promises";
@@ -249,12 +278,13 @@ import {
249
278
  calculateContentHash,
250
279
  sortUtxosByOutpoint
251
280
  } from "@hardkas/artifacts";
281
+ import { deterministicCompare } from "@hardkas/core";
252
282
  function calculateUtxoSetHash(utxos) {
253
283
  const sorted = sortUtxosByOutpoint(utxos);
254
284
  return calculateContentHash(sorted);
255
285
  }
256
286
  function calculateAccountsHash(accounts) {
257
- const sorted = [...accounts].sort((a, b) => a.address.localeCompare(b.address));
287
+ const sorted = [...accounts || []].sort((a, b) => deterministicCompare(a.address, b.address));
258
288
  return calculateContentHash(sorted);
259
289
  }
260
290
  function calculateStateHash(state) {
@@ -270,20 +300,26 @@ function createLocalnetSnapshot(state, name) {
270
300
  const accountsHash = calculateAccountsHash(state.accounts);
271
301
  const utxoSetHash = calculateUtxoSetHash(state.utxos);
272
302
  const stateHash = calculateStateHash(state);
273
- const snapshot = {
303
+ const snapshotDraft = {
274
304
  schema: "hardkas.snapshot",
275
305
  hardkasVersion: HARDKAS_VERSION2,
276
306
  version: ARTIFACT_VERSION,
277
307
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
308
+ // hardkas-determinism-allow: snapshot creation timestamp
278
309
  name,
279
310
  daaScore: state.daaScore,
280
311
  accountsHash,
281
312
  utxoSetHash,
282
313
  stateHash,
283
314
  accounts: JSON.parse(JSON.stringify(state.accounts)),
284
- utxos: JSON.parse(JSON.stringify(sortUtxosByOutpoint(state.utxos)))
315
+ utxos: JSON.parse(JSON.stringify(sortUtxosByOutpoint(state.utxos))),
316
+ networkId: state.networkId,
317
+ mode: state.mode
318
+ };
319
+ const snapshot = {
320
+ ...snapshotDraft,
321
+ contentHash: calculateContentHash(snapshotDraft)
285
322
  };
286
- snapshot.contentHash = calculateContentHash(snapshot);
287
323
  return {
288
324
  ...state,
289
325
  snapshots: [...state.snapshots || [], snapshot]
@@ -343,7 +379,9 @@ import { buildPaymentPlan } from "@hardkas/tx-builder";
343
379
  import {
344
380
  createTxPlanArtifact,
345
381
  createSimulatedTxReceipt,
346
- calculateContentHash as calculateContentHash2
382
+ calculateContentHash as calculateContentHash2,
383
+ HARDKAS_VERSION as HARDKAS_VERSION3,
384
+ ARTIFACT_VERSION as ARTIFACT_VERSION2
347
385
  } from "@hardkas/artifacts";
348
386
  function buildDagContextFromState(state) {
349
387
  if (state.dag) {
@@ -370,12 +408,18 @@ function generateDeterministicTxId(planArtifact, preStateHash, daaScore) {
370
408
  return `simtx_${hash}`;
371
409
  }
372
410
  var DUST_LIMIT_SOMPI = 600n;
373
- function applySimulatedPayment(state, input) {
411
+ function applySimulatedPayment(state, input, ctx) {
374
412
  const errors = [];
375
413
  const preStateHash = calculateStateHash(state);
376
414
  try {
377
415
  const fromAddress = resolveAccountAddressFromState(state, input.from);
416
+ if (!fromAddress) {
417
+ throw new Error(`Sender account/address not found: ${input.from}`);
418
+ }
378
419
  const toAddress = resolveAccountAddressFromState(state, input.to);
420
+ if (!toAddress) {
421
+ throw new Error(`Recipient account/address not found: ${input.to}`);
422
+ }
379
423
  const amountSompi = input.amountSompi;
380
424
  const feeRateSompiPerMass = input.feeRateSompiPerMass ?? 1n;
381
425
  if (amountSompi <= 0n) {
@@ -421,7 +465,8 @@ function applySimulatedPayment(state, input) {
421
465
  from: { input: input.from, address: fromAddress },
422
466
  to: { input: input.to, address: toAddress },
423
467
  amountSompi,
424
- plan
468
+ plan,
469
+ ctx
425
470
  });
426
471
  const nextDaaScore = (BigInt(state.daaScore) + 1n).toString();
427
472
  const txId = generateDeterministicTxId(planArtifact, preStateHash, nextDaaScore);
@@ -462,7 +507,7 @@ function applySimulatedPayment(state, input) {
462
507
  utxos: nextUtxos
463
508
  };
464
509
  const postStateHash = calculateStateHash(nextState);
465
- const receipt = createSimulatedTxReceipt(planArtifact, txId, {
510
+ const receipt = createSimulatedTxReceipt(planArtifact, txId, ctx, {
466
511
  spentUtxoIds,
467
512
  createdUtxoIds,
468
513
  daaScore: nextDaaScore,
@@ -478,29 +523,37 @@ function applySimulatedPayment(state, input) {
478
523
  errors
479
524
  };
480
525
  } catch (error) {
526
+ const errorMessage = error instanceof Error ? error.message : String(error);
481
527
  const daaScore = state.daaScore || "0";
482
- const txId = generateDeterministicFailedTxId(preStateHash, error.message, daaScore);
528
+ const txId = generateDeterministicFailedTxId(preStateHash, errorMessage, daaScore);
483
529
  const receipt = {
484
530
  schema: "hardkas.txReceipt",
531
+ hardkasVersion: HARDKAS_VERSION3,
532
+ version: ARTIFACT_VERSION2,
485
533
  status: "failed",
486
534
  mode: "simulated",
535
+ networkId: state.networkId,
487
536
  txId,
488
537
  createdAt: "1970-01-01T00:00:00.000Z",
489
- errors: [error.message],
538
+ errors: [errorMessage],
490
539
  preStateHash,
491
540
  postStateHash: preStateHash,
492
- dagContext: buildDagContextFromState(state)
541
+ dagContext: buildDagContextFromState(state),
542
+ from: { address: "" },
543
+ to: { address: "" },
544
+ amountSompi: "0",
545
+ feeSompi: "0"
493
546
  };
494
547
  return {
495
548
  ok: false,
496
549
  state,
497
550
  // No mutation
498
551
  receipt,
499
- errors: [error.message]
552
+ errors: [errorMessage]
500
553
  };
501
554
  }
502
555
  }
503
- function applySimulatedPlan(state, planArtifact, options) {
556
+ function applySimulatedPlan(state, planArtifact, ctx, options) {
504
557
  const errors = [];
505
558
  const preStateHash = calculateStateHash(state);
506
559
  try {
@@ -543,7 +596,7 @@ function applySimulatedPlan(state, planArtifact, options) {
543
596
  }
544
597
  const nextState = { ...state, daaScore: nextDaaScore, utxos: nextUtxos };
545
598
  const postStateHash = calculateStateHash(nextState);
546
- const receipt = createSimulatedTxReceipt(planArtifact, txId, {
599
+ const receipt = createSimulatedTxReceipt(planArtifact, txId, ctx, {
547
600
  spentUtxoIds,
548
601
  createdUtxoIds,
549
602
  daaScore: nextDaaScore,
@@ -553,20 +606,28 @@ function applySimulatedPlan(state, planArtifact, options) {
553
606
  });
554
607
  return { ok: true, state: nextState, receipt, planArtifact, errors };
555
608
  } catch (error) {
609
+ const errorMessage = error instanceof Error ? error.message : String(error);
556
610
  const daaScore = state.daaScore || "0";
557
- const txId = generateDeterministicFailedTxId(preStateHash, error.message, daaScore);
611
+ const txId = generateDeterministicFailedTxId(preStateHash, errorMessage, daaScore);
558
612
  const receipt = {
559
613
  schema: "hardkas.txReceipt",
614
+ hardkasVersion: HARDKAS_VERSION3,
615
+ version: ARTIFACT_VERSION2,
560
616
  status: "failed",
561
617
  mode: "simulated",
618
+ networkId: state.networkId,
562
619
  txId,
563
620
  createdAt: "1970-01-01T00:00:00.000Z",
564
- errors: [error.message],
621
+ errors: [errorMessage],
565
622
  preStateHash,
566
623
  postStateHash: preStateHash,
567
- dagContext: buildDagContextFromState(state)
624
+ dagContext: buildDagContextFromState(state),
625
+ from: { address: "" },
626
+ to: { address: "" },
627
+ amountSompi: "0",
628
+ feeSompi: "0"
568
629
  };
569
- return { ok: false, state, receipt, errors: [error.message] };
630
+ return { ok: false, state, receipt, errors: [errorMessage] };
570
631
  }
571
632
  }
572
633
 
@@ -576,7 +637,7 @@ import {
576
637
  diffArtifacts
577
638
  } from "@hardkas/artifacts";
578
639
  import { coreEvents } from "@hardkas/core";
579
- function verifyReplay(state, originalPlan, originalReceipt) {
640
+ function verifyReplay(state, originalPlan, originalReceipt, ctx) {
580
641
  const errors = [];
581
642
  const reportDivergences = [];
582
643
  const currentPlanHash = calculateContentHash3(originalPlan);
@@ -607,7 +668,7 @@ function verifyReplay(state, originalPlan, originalReceipt) {
607
668
  severity: "warning"
608
669
  });
609
670
  }
610
- const result = applySimulatedPlan(state, originalPlan, { txId: originalReceipt.txId });
671
+ const result = applySimulatedPlan(state, originalPlan, ctx, { txId: originalReceipt.txId });
611
672
  const replayReceipt = result.receipt;
612
673
  const diff = diffArtifacts(originalReceipt, replayReceipt);
613
674
  if (!diff.identical) {
@@ -654,8 +715,8 @@ function verifyReplay(state, originalPlan, originalReceipt) {
654
715
  };
655
716
  }
656
717
  async function getSimulatedReplaySummary(txId, options = {}) {
657
- const { loadSimulatedReceipt: loadSimulatedReceipt2 } = await import("./receipts-JSTNZMDD.js");
658
- const { loadSimulatedTrace: loadSimulatedTrace2 } = await import("./traces-HDVV77MQ.js");
718
+ const { loadSimulatedReceipt: loadSimulatedReceipt2 } = await import("./receipts-7RMJMXXG.js");
719
+ const { loadSimulatedTrace: loadSimulatedTrace2 } = await import("./traces-ZUBWSXYB.js");
659
720
  const receipt = await loadSimulatedReceipt2(txId, options);
660
721
  const trace = await loadSimulatedTrace2(txId, options);
661
722
  if (!receipt || !trace) {
@@ -683,6 +744,7 @@ import {
683
744
  findSelectedParent,
684
745
  GENESIS_HASH as SIM_GENESIS_HASH
685
746
  } from "@hardkas/simulator";
747
+ import { deterministicCompare as deterministicCompare2 } from "@hardkas/core";
686
748
  var dagIdMaps = /* @__PURE__ */ new WeakMap();
687
749
  var dagReverseIdMaps = /* @__PURE__ */ new WeakMap();
688
750
  function getIdMap(dag) {
@@ -810,7 +872,7 @@ function moveSink(dag, newSinkId, txProvider) {
810
872
  const daaA = BigInt(a.daaScore);
811
873
  const daaB = BigInt(b.daaScore);
812
874
  if (daaA !== daaB) return daaA < daaB ? -1 : 1;
813
- return a.id.localeCompare(b.id);
875
+ return deterministicCompare2(a.id, b.id);
814
876
  });
815
877
  const acceptedTxIds = [];
816
878
  const displacedTxIds = [];
@@ -918,7 +980,7 @@ function resolveConflictsDeterministically(txs, dag) {
918
980
  const blockA = dag.blocks[a.blockId];
919
981
  const blockB = dag.blocks[b.blockId];
920
982
  if (!blockA || !blockB) {
921
- if (!blockA && !blockB) return a.txId.localeCompare(b.txId);
983
+ if (!blockA && !blockB) return deterministicCompare2(a.txId, b.txId);
922
984
  return !blockA ? 1 : -1;
923
985
  }
924
986
  const inPathA = dag.selectedPathToSink.includes(a.blockId);
@@ -933,8 +995,8 @@ function resolveConflictsDeterministically(txs, dag) {
933
995
  const daaA = BigInt(blockA.daaScore);
934
996
  const daaB = BigInt(blockB.daaScore);
935
997
  if (daaA !== daaB) return daaA < daaB ? -1 : 1;
936
- if (a.blockId !== b.blockId) return a.blockId.localeCompare(b.blockId);
937
- return a.txId.localeCompare(b.txId);
998
+ if (a.blockId !== b.blockId) return deterministicCompare2(a.blockId, b.blockId);
999
+ return deterministicCompare2(a.txId, b.txId);
938
1000
  });
939
1001
  const accepted = [];
940
1002
  const displaced = [];
@@ -1006,8 +1068,10 @@ import { ARTIFACT_SCHEMAS as ARTIFACT_SCHEMAS2, HARDKAS_VERSION as HARDKAS_VERSI
1006
1068
  async function forkFromNetwork(rpc, opts) {
1007
1069
  const info = await rpc.getInfo();
1008
1070
  const networkId = info.networkId || opts.network;
1009
- const currentDaaScore = info.virtualDaaScore?.toString() || "0";
1010
- const targetDaaScore = opts.atDaaScore || currentDaaScore;
1071
+ const targetDaaScore = opts.atDaaScore;
1072
+ if (!targetDaaScore) {
1073
+ throw new Error(`[CRITICAL SEMANTIC ERROR] Implicit 'latest' resolution forbidden. You must explicitly provide atDaaScore.`);
1074
+ }
1011
1075
  const utxos = [];
1012
1076
  for (const address of opts.addresses) {
1013
1077
  const rpcUtxos = await rpc.getUtxosByAddress(address);
@@ -1028,6 +1092,7 @@ async function forkFromNetwork(rpc, opts) {
1028
1092
  hashVersion: "sha256-canonical",
1029
1093
  mode: "simulated",
1030
1094
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1095
+ // hardkas-determinism-allow: fork state creation timestamp
1031
1096
  networkId,
1032
1097
  daaScore: targetDaaScore,
1033
1098
  accounts: opts.addresses.map((addr, i) => ({
@@ -1040,6 +1105,7 @@ async function forkFromNetwork(rpc, opts) {
1040
1105
  rpcUrl: opts.rpcUrl,
1041
1106
  daaScore: targetDaaScore,
1042
1107
  forkedAt: (/* @__PURE__ */ new Date()).toISOString(),
1108
+ // hardkas-determinism-allow: fork source timestamp
1043
1109
  addresses: opts.addresses
1044
1110
  }
1045
1111
  };
@@ -1080,6 +1146,7 @@ export {
1080
1146
  loadSimulatedReceipt,
1081
1147
  loadSimulatedTrace,
1082
1148
  moveSink,
1149
+ reconstructStateAtDaa,
1083
1150
  resetLocalnetState,
1084
1151
  resolveAccountAddress,
1085
1152
  resolveAccountAddressFromState,
@@ -4,7 +4,7 @@ import {
4
4
  listSimulatedReceipts,
5
5
  loadSimulatedReceipt,
6
6
  saveSimulatedReceipt
7
- } from "./chunk-GVBX3TPM.js";
7
+ } from "./chunk-M5T6T465.js";
8
8
  export {
9
9
  getDefaultReceiptsDir,
10
10
  getReceiptPath,
@@ -4,7 +4,7 @@ import {
4
4
  listSimulatedTraces,
5
5
  loadSimulatedTrace,
6
6
  saveSimulatedTrace
7
- } from "./chunk-DPHHOGGK.js";
7
+ } from "./chunk-6AICYLVR.js";
8
8
  export {
9
9
  getDefaultTracesDir,
10
10
  getTracePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/localnet",
3
- "version": "0.5.5-alpha",
3
+ "version": "0.6.1-alpha",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -8,12 +8,12 @@
8
8
  ".": "./dist/index.js"
9
9
  },
10
10
  "dependencies": {
11
- "@hardkas/core": "0.5.5-alpha",
12
- "@hardkas/artifacts": "0.5.5-alpha",
13
- "@hardkas/kaspa-rpc": "0.5.5-alpha",
14
- "@hardkas/query": "0.5.5-alpha",
15
- "@hardkas/tx-builder": "0.5.5-alpha",
16
- "@hardkas/simulator": "0.5.5-alpha"
11
+ "@hardkas/artifacts": "0.6.1-alpha",
12
+ "@hardkas/core": "0.6.1-alpha",
13
+ "@hardkas/simulator": "0.6.1-alpha",
14
+ "@hardkas/query": "0.6.1-alpha",
15
+ "@hardkas/tx-builder": "0.6.1-alpha",
16
+ "@hardkas/kaspa-rpc": "0.6.1-alpha"
17
17
  },
18
18
  "devDependencies": {
19
19
  "fast-check": "^4.8.0",