@hardkas/simulator 0.8.19-alpha → 0.9.0-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/index.d.ts CHANGED
@@ -374,4 +374,164 @@ declare function profileAndCompare(opts: {
374
374
  comparison?: MassComparison;
375
375
  };
376
376
 
377
- export { ApproxGhostdagEngine, type BlockHash, type BlueWorkType, type CandidateColor, type CompactGhostdagData, DEFAULT_K, type DagMetrics, GENESIS_HASH, type GhostdagData, GhostdagStore, type MassBreakdown, type MassComparison, type MassSnapshot, type MassSnapshotStore, type ScenarioConfig, type ScenarioResult, type SimBlock, type SimBlockHeader, type SimulationResult, type SortableBlock, type TxLifecyclePhase, TxSimulator, type TxTraceEvent, blockBlueScore, blockBlueWork, blockHash, blockParents, compactFromFull, compareMassProfiles, compareSortableBlocks, computeDagMetrics, createTraceId, findSelectedParent, formatMassComparison, formatMassProfile, formatScenarioReport, genesisGhostdagData, headerWork, isDagAncestorOf, loadMassSnapshot, orderedMergesetWithoutSelectedParent, pastSet, profileAndCompare, profileMass, runAllScenarios, runDiamondDag, runForkResolution, runLinearChain, runWideDag, saveMassSnapshot, sortBlocks, unorderedMergesetWithoutSelectedParent };
377
+ declare const SILVER_SIMULATOR_FEE_SOMPI = 2000n;
378
+ declare const SILVER_SIMULATOR_CREATED_AT = "1970-01-01T00:00:00.000Z";
379
+ declare const SILVER_SIMULATOR_VERSION = "1.0.0-alpha";
380
+ type SilverSimulationStatus = "SIMULATED_ACCEPTED";
381
+ type SilverSimulationErrorCode = "SILVERSCRIPT_REDEEM_HASH_MISMATCH" | "SILVERSCRIPT_LOCKING_SCRIPT_MISMATCH" | "SILVERSCRIPT_SIGNATURE_SCRIPT_NOT_PUSH_ONLY" | "SILVERSCRIPT_ARGS_HASH_MISMATCH" | "SILVERSCRIPT_UTXO_ALREADY_SPENT" | "SILVERSCRIPT_NETWORK_UNSUPPORTED" | "SILVERSCRIPT_AMOUNT_TOO_SMALL" | "SILVERSCRIPT_DEPLOY_RECEIPT_NOT_FOUND" | "SILVERSCRIPT_SCHEMA_INVALID" | "SILVERSCRIPT_INVALID_HEX" | "SILVERSCRIPT_EXPECTED_OUTPUTS_REQUIRED" | "SILVERSCRIPT_SIGNATURE_SCRIPT_MISMATCH";
382
+ declare class SilverSimulationError extends Error {
383
+ readonly code: SilverSimulationErrorCode;
384
+ constructor(code: SilverSimulationErrorCode, message: string);
385
+ }
386
+ interface SilverDeployPlanArtifactLike {
387
+ schema: "hardkas.silver.deployPlan";
388
+ hardkasVersion?: string;
389
+ version?: string;
390
+ hashVersion?: number | string;
391
+ networkId: string;
392
+ mode?: string;
393
+ createdAt?: string;
394
+ contentHash?: string;
395
+ compileArtifactHash: string;
396
+ compiledScriptHash: string;
397
+ redeemScriptHex: string;
398
+ redeemScriptHash: string;
399
+ lockingScriptHex: string;
400
+ scriptPublicKeyVersion: number;
401
+ amountSompi: string;
402
+ deployerAddress: string;
403
+ }
404
+ interface SilverArgArtifactLike {
405
+ type: "hex";
406
+ value: string;
407
+ }
408
+ interface SilverSpendPlanArtifactLike {
409
+ schema: "hardkas.silver.spendPlan";
410
+ hardkasVersion?: string;
411
+ version?: string;
412
+ hashVersion?: number | string;
413
+ networkId: string;
414
+ mode?: string;
415
+ createdAt?: string;
416
+ contentHash?: string;
417
+ deployArtifactHash: string;
418
+ compileArtifactHash: string;
419
+ redeemScriptHash: string;
420
+ lockingScriptHex: string;
421
+ contractUtxoRef: {
422
+ transactionId: string;
423
+ index: number;
424
+ };
425
+ args: SilverArgArtifactLike[];
426
+ argsHash: string;
427
+ signatureScriptHex: string;
428
+ expectedOutputs: SilverExpectedOutput[];
429
+ }
430
+ interface SilverExpectedOutput {
431
+ address: string;
432
+ amountSompi: string;
433
+ scriptHash?: string;
434
+ }
435
+ interface SilverSyntheticOutpoint {
436
+ transactionId: string;
437
+ index: number;
438
+ }
439
+ interface SilverDeploySimulationReceipt {
440
+ schema: "hardkas.silver.deploySimulation";
441
+ hardkasVersion: string;
442
+ version: "1.0.0-alpha";
443
+ hashVersion: number;
444
+ networkId: "simnet";
445
+ mode: "simulated";
446
+ createdAt: string;
447
+ deployPlanHash: string;
448
+ compileArtifactHash: string;
449
+ compiledScriptHash: string;
450
+ redeemScriptHex: string;
451
+ redeemScriptHash: string;
452
+ lockingScriptHex: string;
453
+ scriptPublicKeyVersion: 0;
454
+ simulatedDeployTxId: string;
455
+ syntheticOutpoint: SilverSyntheticOutpoint;
456
+ amountSompi: string;
457
+ feeSompi: string;
458
+ status: SilverSimulationStatus;
459
+ lineage: {
460
+ artifactId: string;
461
+ lineageId: string;
462
+ parentArtifactId: string;
463
+ rootArtifactId: string;
464
+ sequence: number;
465
+ };
466
+ contentHash: string;
467
+ artifactId: string;
468
+ }
469
+ interface SilverSpendSimulationReceipt {
470
+ schema: "hardkas.silver.spendSimulation";
471
+ hardkasVersion: string;
472
+ version: "1.0.0-alpha";
473
+ hashVersion: number;
474
+ networkId: "simnet";
475
+ mode: "simulated";
476
+ createdAt: string;
477
+ deploySimulationHash: string;
478
+ spendPlanHash: string;
479
+ redeemScriptHash: string;
480
+ lockingScriptHex: string;
481
+ signatureScriptHex: string;
482
+ simulatedSpendTxId: string;
483
+ spentOutpoint: SilverSyntheticOutpoint;
484
+ expectedOutputs: SilverExpectedOutput[];
485
+ feeSompi: string;
486
+ status: SilverSimulationStatus;
487
+ lineage: {
488
+ artifactId: string;
489
+ lineageId: string;
490
+ parentArtifactId: string;
491
+ rootArtifactId: string;
492
+ sequence: number;
493
+ };
494
+ contentHash: string;
495
+ artifactId: string;
496
+ }
497
+ interface SilverSimulatedUtxo {
498
+ outpoint: SilverSyntheticOutpoint;
499
+ deploySimulationHash: string;
500
+ deployPlanHash: string;
501
+ redeemScriptHex: string;
502
+ redeemScriptHash: string;
503
+ lockingScriptHex: string;
504
+ amountSompi: string;
505
+ networkId: "simnet";
506
+ spent: boolean;
507
+ spentByTxId?: string;
508
+ }
509
+ interface SilverSimulationState {
510
+ schema: "hardkas.silver.simulationState.v1";
511
+ version: "1.0.0-alpha";
512
+ networkId: "simnet";
513
+ mode: "simulated";
514
+ deployReceipts: Record<string, SilverDeploySimulationReceipt>;
515
+ utxos: Record<string, SilverSimulatedUtxo>;
516
+ spentOutpoints: string[];
517
+ }
518
+ interface SilverDeploySimulationResult {
519
+ receipt: SilverDeploySimulationReceipt;
520
+ state: SilverSimulationState;
521
+ }
522
+ interface SilverSpendSimulationResult {
523
+ receipt: SilverSpendSimulationReceipt;
524
+ state: SilverSimulationState;
525
+ }
526
+ interface SilverSimulationOptions {
527
+ hardkasVersion?: string;
528
+ createdAt?: string;
529
+ }
530
+ declare function createSilverSimulationState(): SilverSimulationState;
531
+ declare function simulateSilverDeploy(deployPlanArtifact: SilverDeployPlanArtifactLike, options?: SilverSimulationOptions): SilverDeploySimulationResult;
532
+ declare function simulateSilverSpend(spendPlanArtifact: SilverSpendPlanArtifactLike, simulatedState: SilverSimulationState, options?: SilverSimulationOptions): SilverSpendSimulationResult;
533
+ declare function calculateSilverArgsHash(args: readonly SilverArgArtifactLike[]): string;
534
+ declare function outpointKey(outpoint: SilverSyntheticOutpoint): string;
535
+ declare function parsePushOnlyScript(signatureScriptHex: string): string[];
536
+
537
+ export { ApproxGhostdagEngine, type BlockHash, type BlueWorkType, type CandidateColor, type CompactGhostdagData, DEFAULT_K, type DagMetrics, GENESIS_HASH, type GhostdagData, GhostdagStore, type MassBreakdown, type MassComparison, type MassSnapshot, type MassSnapshotStore, SILVER_SIMULATOR_CREATED_AT, SILVER_SIMULATOR_FEE_SOMPI, SILVER_SIMULATOR_VERSION, type ScenarioConfig, type ScenarioResult, type SilverArgArtifactLike, type SilverDeployPlanArtifactLike, type SilverDeploySimulationReceipt, type SilverDeploySimulationResult, type SilverExpectedOutput, type SilverSimulatedUtxo, SilverSimulationError, type SilverSimulationErrorCode, type SilverSimulationOptions, type SilverSimulationState, type SilverSimulationStatus, type SilverSpendPlanArtifactLike, type SilverSpendSimulationReceipt, type SilverSpendSimulationResult, type SimBlock, type SimBlockHeader, type SimulationResult, type SortableBlock, type TxLifecyclePhase, TxSimulator, type TxTraceEvent, blockBlueScore, blockBlueWork, blockHash, blockParents, calculateSilverArgsHash, compactFromFull, compareMassProfiles, compareSortableBlocks, computeDagMetrics, createSilverSimulationState, createTraceId, findSelectedParent, formatMassComparison, formatMassProfile, formatScenarioReport, genesisGhostdagData, headerWork, isDagAncestorOf, loadMassSnapshot, orderedMergesetWithoutSelectedParent, outpointKey, parsePushOnlyScript, pastSet, profileAndCompare, profileMass, runAllScenarios, runDiamondDag, runForkResolution, runLinearChain, runWideDag, saveMassSnapshot, simulateSilverDeploy, simulateSilverSpend, sortBlocks, unorderedMergesetWithoutSelectedParent };
package/dist/index.js CHANGED
@@ -757,20 +757,443 @@ function reviveSnapshot(snapshot) {
757
757
  };
758
758
  return snapshot;
759
759
  }
760
+
761
+ // src/silver-simulator.ts
762
+ import { createHash as createHash2 } from "crypto";
763
+ import { createKaspaP2shBlake2bLock } from "@hardkas/core";
764
+ var SILVER_SIMULATOR_FEE_SOMPI = 2000n;
765
+ var SILVER_SIMULATOR_CREATED_AT = "1970-01-01T00:00:00.000Z";
766
+ var SILVER_SIMULATOR_VERSION = "1.0.0-alpha";
767
+ var CURRENT_HASH_VERSION = 4;
768
+ var SilverSimulationError = class extends Error {
769
+ code;
770
+ constructor(code, message) {
771
+ super(message);
772
+ this.name = "SilverSimulationError";
773
+ this.code = code;
774
+ }
775
+ };
776
+ function createSilverSimulationState() {
777
+ return {
778
+ schema: "hardkas.silver.simulationState.v1",
779
+ version: SILVER_SIMULATOR_VERSION,
780
+ networkId: "simnet",
781
+ mode: "simulated",
782
+ deployReceipts: {},
783
+ utxos: {},
784
+ spentOutpoints: []
785
+ };
786
+ }
787
+ function simulateSilverDeploy(deployPlanArtifact, options = {}) {
788
+ if (deployPlanArtifact.schema !== "hardkas.silver.deployPlan") {
789
+ throw new SilverSimulationError(
790
+ "SILVERSCRIPT_SCHEMA_INVALID",
791
+ "Expected hardkas.silver.deployPlan."
792
+ );
793
+ }
794
+ assertSimnet(deployPlanArtifact.networkId);
795
+ assertHex(deployPlanArtifact.redeemScriptHex, "redeemScriptHex");
796
+ const amountSompi = parseSompi(deployPlanArtifact.amountSompi);
797
+ if (amountSompi <= SILVER_SIMULATOR_FEE_SOMPI) {
798
+ throw new SilverSimulationError(
799
+ "SILVERSCRIPT_AMOUNT_TOO_SMALL",
800
+ "Deploy amount must be greater than the simulator fee."
801
+ );
802
+ }
803
+ const lock = createKaspaP2shBlake2bLock(deployPlanArtifact.redeemScriptHex);
804
+ if (lock.redeemScriptHash !== deployPlanArtifact.redeemScriptHash) {
805
+ throw new SilverSimulationError(
806
+ "SILVERSCRIPT_REDEEM_HASH_MISMATCH",
807
+ "redeemScriptHash must equal blake2b32(raw redeem script bytes)."
808
+ );
809
+ }
810
+ if (lock.lockingScriptHex !== deployPlanArtifact.lockingScriptHex) {
811
+ throw new SilverSimulationError(
812
+ "SILVERSCRIPT_LOCKING_SCRIPT_MISMATCH",
813
+ "lockingScriptHex must equal aa20 + redeemScriptHash + 87."
814
+ );
815
+ }
816
+ if (deployPlanArtifact.scriptPublicKeyVersion !== 0) {
817
+ throw new SilverSimulationError(
818
+ "SILVERSCRIPT_LOCKING_SCRIPT_MISMATCH",
819
+ "scriptPublicKeyVersion must be 0 for this local simulator."
820
+ );
821
+ }
822
+ const deployPlanHash = artifactHash(deployPlanArtifact);
823
+ const simulatedDeployTxId = deterministicHex({
824
+ kind: "hardkas.silver.simulatedDeployTx",
825
+ deployPlanHash,
826
+ redeemScriptHash: deployPlanArtifact.redeemScriptHash,
827
+ amountSompi: deployPlanArtifact.amountSompi
828
+ });
829
+ const syntheticOutpoint = {
830
+ transactionId: simulatedDeployTxId,
831
+ index: 0
832
+ };
833
+ const draft = {
834
+ schema: "hardkas.silver.deploySimulation",
835
+ hardkasVersion: options.hardkasVersion ?? deployPlanArtifact.hardkasVersion ?? "0.9.0-alpha",
836
+ version: SILVER_SIMULATOR_VERSION,
837
+ hashVersion: CURRENT_HASH_VERSION,
838
+ networkId: "simnet",
839
+ mode: "simulated",
840
+ createdAt: options.createdAt ?? SILVER_SIMULATOR_CREATED_AT,
841
+ deployPlanHash,
842
+ compileArtifactHash: deployPlanArtifact.compileArtifactHash,
843
+ compiledScriptHash: deployPlanArtifact.compiledScriptHash,
844
+ redeemScriptHex: deployPlanArtifact.redeemScriptHex,
845
+ redeemScriptHash: deployPlanArtifact.redeemScriptHash,
846
+ lockingScriptHex: deployPlanArtifact.lockingScriptHex,
847
+ scriptPublicKeyVersion: 0,
848
+ simulatedDeployTxId,
849
+ syntheticOutpoint,
850
+ amountSompi: amountSompi.toString(),
851
+ feeSompi: SILVER_SIMULATOR_FEE_SOMPI.toString(),
852
+ status: "SIMULATED_ACCEPTED",
853
+ lineage: {
854
+ artifactId: `deploy-sim-${deployPlanHash.slice(0, 16)}`,
855
+ lineageId: `silver-lineage-${deployPlanHash.slice(0, 16)}`,
856
+ parentArtifactId: deployPlanHash,
857
+ rootArtifactId: deployPlanHash,
858
+ sequence: 1
859
+ }
860
+ };
861
+ const receipt = finalizeArtifact(draft, "silverdeploysim");
862
+ const state = createSilverSimulationState();
863
+ state.deployReceipts[receipt.contentHash] = receipt;
864
+ state.utxos[outpointKey(syntheticOutpoint)] = {
865
+ outpoint: syntheticOutpoint,
866
+ deploySimulationHash: receipt.contentHash,
867
+ deployPlanHash,
868
+ redeemScriptHex: deployPlanArtifact.redeemScriptHex,
869
+ redeemScriptHash: deployPlanArtifact.redeemScriptHash,
870
+ lockingScriptHex: deployPlanArtifact.lockingScriptHex,
871
+ amountSompi: amountSompi.toString(),
872
+ networkId: "simnet",
873
+ spent: false
874
+ };
875
+ return {
876
+ receipt,
877
+ state: normalizeState(state)
878
+ };
879
+ }
880
+ function simulateSilverSpend(spendPlanArtifact, simulatedState, options = {}) {
881
+ if (spendPlanArtifact.schema !== "hardkas.silver.spendPlan") {
882
+ throw new SilverSimulationError(
883
+ "SILVERSCRIPT_SCHEMA_INVALID",
884
+ "Expected hardkas.silver.spendPlan."
885
+ );
886
+ }
887
+ assertSimnet(spendPlanArtifact.networkId);
888
+ if (simulatedState.networkId !== "simnet") {
889
+ throw new SilverSimulationError(
890
+ "SILVERSCRIPT_NETWORK_UNSUPPORTED",
891
+ "Silver/Toccata simulation state must be simnet."
892
+ );
893
+ }
894
+ if (!Array.isArray(spendPlanArtifact.expectedOutputs) || spendPlanArtifact.expectedOutputs.length === 0) {
895
+ throw new SilverSimulationError(
896
+ "SILVERSCRIPT_EXPECTED_OUTPUTS_REQUIRED",
897
+ "Spend simulation requires explicit expectedOutputs."
898
+ );
899
+ }
900
+ const key = outpointKey(spendPlanArtifact.contractUtxoRef);
901
+ const utxo = simulatedState.utxos[key];
902
+ const deployReceipt = simulatedState.deployReceipts[spendPlanArtifact.deployArtifactHash] ?? Object.values(simulatedState.deployReceipts).find((receipt2) => {
903
+ return outpointKey(receipt2.syntheticOutpoint) === key;
904
+ });
905
+ if (!utxo || !deployReceipt) {
906
+ throw new SilverSimulationError(
907
+ "SILVERSCRIPT_DEPLOY_RECEIPT_NOT_FOUND",
908
+ `No deploy simulation receipt exists for ${key}.`
909
+ );
910
+ }
911
+ if (deployReceipt.networkId !== spendPlanArtifact.networkId || utxo.networkId !== spendPlanArtifact.networkId) {
912
+ throw new SilverSimulationError(
913
+ "SILVERSCRIPT_NETWORK_UNSUPPORTED",
914
+ "Spend plan network must match the deployed synthetic UTXO network."
915
+ );
916
+ }
917
+ if (utxo.spent || simulatedState.spentOutpoints.includes(key)) {
918
+ throw new SilverSimulationError(
919
+ "SILVERSCRIPT_UTXO_ALREADY_SPENT",
920
+ `Synthetic UTXO ${key} has already been spent.`
921
+ );
922
+ }
923
+ const pushes = parsePushOnlyScript(spendPlanArtifact.signatureScriptHex);
924
+ const redeemScriptHex = pushes.at(-1);
925
+ if (!redeemScriptHex) {
926
+ throw new SilverSimulationError(
927
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_NOT_PUSH_ONLY",
928
+ "signatureScriptHex must end with a pushed redeem script."
929
+ );
930
+ }
931
+ if (redeemScriptHex !== utxo.redeemScriptHex.toLowerCase()) {
932
+ throw new SilverSimulationError(
933
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_MISMATCH",
934
+ "Redeem script must be the last push and match the deployed script."
935
+ );
936
+ }
937
+ const lock = createKaspaP2shBlake2bLock(redeemScriptHex);
938
+ if (lock.redeemScriptHash !== spendPlanArtifact.redeemScriptHash) {
939
+ throw new SilverSimulationError(
940
+ "SILVERSCRIPT_REDEEM_HASH_MISMATCH",
941
+ "Spend redeemScriptHash does not match pushed redeem script."
942
+ );
943
+ }
944
+ if (lock.lockingScriptHex !== spendPlanArtifact.lockingScriptHex) {
945
+ throw new SilverSimulationError(
946
+ "SILVERSCRIPT_LOCKING_SCRIPT_MISMATCH",
947
+ "Spend lockingScriptHex does not match pushed redeem script."
948
+ );
949
+ }
950
+ if (calculateSilverArgsHash(spendPlanArtifact.args) !== spendPlanArtifact.argsHash) {
951
+ throw new SilverSimulationError(
952
+ "SILVERSCRIPT_ARGS_HASH_MISMATCH",
953
+ "Spend argsHash does not match args."
954
+ );
955
+ }
956
+ const argValues = spendPlanArtifact.args.map((arg) => {
957
+ if (arg.type !== "hex" || !isHex(arg.value)) {
958
+ throw new SilverSimulationError(
959
+ "SILVERSCRIPT_INVALID_HEX",
960
+ "Spend args must be hex push values."
961
+ );
962
+ }
963
+ return arg.value.toLowerCase();
964
+ });
965
+ const pushedArgs = pushes.slice(0, -1);
966
+ if (JSON.stringify(pushedArgs) !== JSON.stringify(argValues)) {
967
+ throw new SilverSimulationError(
968
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_MISMATCH",
969
+ "signatureScriptHex args do not match spend plan args."
970
+ );
971
+ }
972
+ const inputAmount = BigInt(utxo.amountSompi);
973
+ const outputTotal = spendPlanArtifact.expectedOutputs.reduce((sum, output) => {
974
+ return sum + parseSompi(output.amountSompi);
975
+ }, 0n);
976
+ if (outputTotal <= 0n || outputTotal + SILVER_SIMULATOR_FEE_SOMPI > inputAmount) {
977
+ throw new SilverSimulationError(
978
+ "SILVERSCRIPT_AMOUNT_TOO_SMALL",
979
+ "Synthetic UTXO amount must cover expectedOutputs plus simulator fee."
980
+ );
981
+ }
982
+ const spendPlanHash = artifactHash(spendPlanArtifact);
983
+ const simulatedSpendTxId = deterministicHex({
984
+ kind: "hardkas.silver.simulatedSpendTx",
985
+ spendPlanHash,
986
+ deploySimulationHash: deployReceipt.contentHash,
987
+ spentOutpoint: key,
988
+ expectedOutputs: spendPlanArtifact.expectedOutputs
989
+ });
990
+ const draft = {
991
+ schema: "hardkas.silver.spendSimulation",
992
+ hardkasVersion: options.hardkasVersion ?? spendPlanArtifact.hardkasVersion ?? "0.9.0-alpha",
993
+ version: SILVER_SIMULATOR_VERSION,
994
+ hashVersion: CURRENT_HASH_VERSION,
995
+ networkId: "simnet",
996
+ mode: "simulated",
997
+ createdAt: options.createdAt ?? SILVER_SIMULATOR_CREATED_AT,
998
+ deploySimulationHash: deployReceipt.contentHash,
999
+ spendPlanHash,
1000
+ redeemScriptHash: spendPlanArtifact.redeemScriptHash,
1001
+ lockingScriptHex: spendPlanArtifact.lockingScriptHex,
1002
+ signatureScriptHex: spendPlanArtifact.signatureScriptHex,
1003
+ simulatedSpendTxId,
1004
+ spentOutpoint: spendPlanArtifact.contractUtxoRef,
1005
+ expectedOutputs: spendPlanArtifact.expectedOutputs,
1006
+ feeSompi: SILVER_SIMULATOR_FEE_SOMPI.toString(),
1007
+ status: "SIMULATED_ACCEPTED",
1008
+ lineage: {
1009
+ artifactId: `spend-sim-${spendPlanHash.slice(0, 16)}`,
1010
+ lineageId: deployReceipt.lineage.lineageId,
1011
+ parentArtifactId: spendPlanHash,
1012
+ rootArtifactId: deployReceipt.lineage.rootArtifactId,
1013
+ sequence: 2
1014
+ }
1015
+ };
1016
+ const receipt = finalizeArtifact(draft, "silverspendsim");
1017
+ const nextState = cloneState(simulatedState);
1018
+ nextState.utxos[key] = {
1019
+ ...utxo,
1020
+ spent: true,
1021
+ spentByTxId: simulatedSpendTxId
1022
+ };
1023
+ nextState.spentOutpoints = Array.from(/* @__PURE__ */ new Set([...nextState.spentOutpoints, key])).sort();
1024
+ return {
1025
+ receipt,
1026
+ state: normalizeState(nextState)
1027
+ };
1028
+ }
1029
+ function calculateSilverArgsHash(args) {
1030
+ return createHash2("sha256").update(JSON.stringify(args)).digest("hex");
1031
+ }
1032
+ function outpointKey(outpoint) {
1033
+ return `${outpoint.transactionId}:${outpoint.index}`;
1034
+ }
1035
+ function parsePushOnlyScript(signatureScriptHex) {
1036
+ assertHex(signatureScriptHex, "signatureScriptHex");
1037
+ const pushes = [];
1038
+ let offset = 0;
1039
+ while (offset < signatureScriptHex.length) {
1040
+ const opcode = readByte(signatureScriptHex, offset);
1041
+ offset += 2;
1042
+ let byteCount;
1043
+ if (opcode === 0) {
1044
+ byteCount = 0;
1045
+ } else if (opcode >= 1 && opcode <= 75) {
1046
+ byteCount = opcode;
1047
+ } else if (opcode === 76) {
1048
+ byteCount = readByte(signatureScriptHex, offset);
1049
+ offset += 2;
1050
+ } else if (opcode === 77) {
1051
+ byteCount = readLittleEndian(signatureScriptHex, offset, 2);
1052
+ offset += 4;
1053
+ } else if (opcode === 78) {
1054
+ byteCount = readLittleEndian(signatureScriptHex, offset, 4);
1055
+ offset += 8;
1056
+ } else {
1057
+ throw new SilverSimulationError(
1058
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_NOT_PUSH_ONLY",
1059
+ `Non-push opcode 0x${opcode.toString(16)} encountered.`
1060
+ );
1061
+ }
1062
+ const hexCount = byteCount * 2;
1063
+ const end = offset + hexCount;
1064
+ if (end > signatureScriptHex.length) {
1065
+ throw new SilverSimulationError(
1066
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_NOT_PUSH_ONLY",
1067
+ "Truncated pushdata in signatureScriptHex."
1068
+ );
1069
+ }
1070
+ pushes.push(signatureScriptHex.slice(offset, end).toLowerCase());
1071
+ offset = end;
1072
+ }
1073
+ return pushes;
1074
+ }
1075
+ function assertSimnet(networkId) {
1076
+ if (networkId !== "simnet") {
1077
+ throw new SilverSimulationError(
1078
+ "SILVERSCRIPT_NETWORK_UNSUPPORTED",
1079
+ "Silver/Toccata simulator only supports local simnet."
1080
+ );
1081
+ }
1082
+ }
1083
+ function assertHex(value, field) {
1084
+ if (!isHex(value)) {
1085
+ throw new SilverSimulationError(
1086
+ "SILVERSCRIPT_INVALID_HEX",
1087
+ `${field} must be even-length hex.`
1088
+ );
1089
+ }
1090
+ }
1091
+ function isHex(value) {
1092
+ return typeof value === "string" && value.length % 2 === 0 && /^[0-9a-fA-F]*$/.test(value);
1093
+ }
1094
+ function calculateContentHash(value, _version = CURRENT_HASH_VERSION) {
1095
+ return createHash2("sha256").update(canonicalStringify(value)).digest("hex");
1096
+ }
1097
+ function canonicalStringify(value) {
1098
+ if (typeof value === "bigint") {
1099
+ return JSON.stringify(`n:${value.toString()}`);
1100
+ }
1101
+ if (value === null || typeof value !== "object") {
1102
+ return JSON.stringify(value);
1103
+ }
1104
+ if (Array.isArray(value)) {
1105
+ return `[${value.map((item) => canonicalStringify(item)).join(",")}]`;
1106
+ }
1107
+ const exclusions = /* @__PURE__ */ new Set([
1108
+ "contentHash",
1109
+ "artifactId",
1110
+ "hashVersion",
1111
+ "createdAt",
1112
+ "hardkasVersion",
1113
+ "status"
1114
+ ]);
1115
+ const record = value;
1116
+ return `{${Object.keys(record).filter((key) => !exclusions.has(key) && record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalStringify(record[key])}`).join(",")}}`;
1117
+ }
1118
+ function parseSompi(value) {
1119
+ if (!/^[0-9]+$/.test(value)) {
1120
+ throw new SilverSimulationError(
1121
+ "SILVERSCRIPT_AMOUNT_TOO_SMALL",
1122
+ "Sompi values must be unsigned integer strings."
1123
+ );
1124
+ }
1125
+ return BigInt(value);
1126
+ }
1127
+ function artifactHash(value) {
1128
+ return value.contentHash ?? calculateContentHash(value, CURRENT_HASH_VERSION);
1129
+ }
1130
+ function deterministicHex(value) {
1131
+ return calculateContentHash(value, CURRENT_HASH_VERSION);
1132
+ }
1133
+ function finalizeArtifact(artifact, prefix) {
1134
+ const contentHash = calculateContentHash(artifact, CURRENT_HASH_VERSION);
1135
+ return {
1136
+ ...artifact,
1137
+ contentHash,
1138
+ artifactId: `${prefix}-${contentHash.slice(0, 16)}`
1139
+ };
1140
+ }
1141
+ function cloneState(state) {
1142
+ return JSON.parse(JSON.stringify(state));
1143
+ }
1144
+ function normalizeState(state) {
1145
+ return {
1146
+ ...state,
1147
+ deployReceipts: Object.fromEntries(
1148
+ Object.entries(state.deployReceipts).sort(([a], [b]) => a.localeCompare(b))
1149
+ ),
1150
+ utxos: Object.fromEntries(
1151
+ Object.entries(state.utxos).sort(([a], [b]) => a.localeCompare(b))
1152
+ ),
1153
+ spentOutpoints: [...state.spentOutpoints].sort()
1154
+ };
1155
+ }
1156
+ function readByte(hex, offset) {
1157
+ const raw = hex.slice(offset, offset + 2);
1158
+ if (raw.length !== 2) {
1159
+ throw new SilverSimulationError(
1160
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_NOT_PUSH_ONLY",
1161
+ "Truncated opcode in signatureScriptHex."
1162
+ );
1163
+ }
1164
+ return parseInt(raw, 16);
1165
+ }
1166
+ function readLittleEndian(hex, offset, byteCount) {
1167
+ const raw = hex.slice(offset, offset + byteCount * 2);
1168
+ if (raw.length !== byteCount * 2) {
1169
+ throw new SilverSimulationError(
1170
+ "SILVERSCRIPT_SIGNATURE_SCRIPT_NOT_PUSH_ONLY",
1171
+ "Truncated pushdata length in signatureScriptHex."
1172
+ );
1173
+ }
1174
+ const bytes = raw.match(/../g) ?? [];
1175
+ return parseInt(bytes.reverse().join(""), 16);
1176
+ }
760
1177
  export {
761
1178
  ApproxGhostdagEngine,
762
1179
  DEFAULT_K,
763
1180
  GENESIS_HASH,
764
1181
  GhostdagStore,
1182
+ SILVER_SIMULATOR_CREATED_AT,
1183
+ SILVER_SIMULATOR_FEE_SOMPI,
1184
+ SILVER_SIMULATOR_VERSION,
1185
+ SilverSimulationError,
765
1186
  TxSimulator,
766
1187
  blockBlueScore,
767
1188
  blockBlueWork,
768
1189
  blockHash,
769
1190
  blockParents,
1191
+ calculateSilverArgsHash,
770
1192
  compactFromFull,
771
1193
  compareMassProfiles,
772
1194
  compareSortableBlocks,
773
1195
  computeDagMetrics,
1196
+ createSilverSimulationState,
774
1197
  createTraceId,
775
1198
  findSelectedParent,
776
1199
  formatMassComparison,
@@ -781,6 +1204,8 @@ export {
781
1204
  isDagAncestorOf,
782
1205
  loadMassSnapshot,
783
1206
  orderedMergesetWithoutSelectedParent,
1207
+ outpointKey,
1208
+ parsePushOnlyScript,
784
1209
  pastSet,
785
1210
  profileAndCompare,
786
1211
  profileMass,
@@ -790,6 +1215,8 @@ export {
790
1215
  runLinearChain,
791
1216
  runWideDag,
792
1217
  saveMassSnapshot,
1218
+ simulateSilverDeploy,
1219
+ simulateSilverSpend,
793
1220
  sortBlocks,
794
1221
  unorderedMergesetWithoutSelectedParent
795
1222
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardkas/simulator",
3
- "version": "0.8.19-alpha",
3
+ "version": "0.9.0-alpha",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -12,8 +12,8 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@hardkas/core": "0.8.19-alpha",
16
- "@hardkas/tx-builder": "0.8.19-alpha"
15
+ "@hardkas/core": "0.9.0-alpha",
16
+ "@hardkas/tx-builder": "0.9.0-alpha"
17
17
  },
18
18
  "devDependencies": {
19
19
  "tsup": "^8.3.5",