@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.
- package/dist/{chunk-DPHHOGGK.js → chunk-6AICYLVR.js} +3 -2
- package/dist/{chunk-GVBX3TPM.js → chunk-M5T6T465.js} +3 -2
- package/dist/index.d.ts +17 -8
- package/dist/index.js +97 -30
- package/dist/{receipts-JSTNZMDD.js → receipts-7RMJMXXG.js} +1 -1
- package/dist/{traces-HDVV77MQ.js → traces-ZUBWSXYB.js} +1 -1
- package/package.json +7 -7
|
@@ -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", "
|
|
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
|
|
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", "
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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,
|
|
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: [
|
|
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: [
|
|
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,
|
|
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: [
|
|
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: [
|
|
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-
|
|
658
|
-
const { loadSimulatedTrace: loadSimulatedTrace2 } = await import("./traces-
|
|
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
|
|
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
|
|
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
|
|
937
|
-
return a.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
|
|
1010
|
-
|
|
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,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardkas/localnet",
|
|
3
|
-
"version": "0.
|
|
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/
|
|
12
|
-
"@hardkas/
|
|
13
|
-
"@hardkas/
|
|
14
|
-
"@hardkas/query": "0.
|
|
15
|
-
"@hardkas/tx-builder": "0.
|
|
16
|
-
"@hardkas/
|
|
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",
|