@midnight-ntwrk/wallet-sdk-capabilities 4.0.0-beta.2 → 4.0.0-beta.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.
Files changed (68) hide show
  1. package/README.md +27 -3
  2. package/dist/chainVersion/chainVersionProbe.d.ts +95 -0
  3. package/dist/chainVersion/chainVersionProbe.js +83 -0
  4. package/dist/chainVersion/index.d.ts +1 -0
  5. package/dist/chainVersion/index.js +13 -0
  6. package/dist/codecs/index.d.ts +1 -0
  7. package/dist/codecs/index.js +13 -0
  8. package/dist/codecs/ledgerParameters.d.ts +81 -0
  9. package/dist/codecs/ledgerParameters.js +63 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.js +3 -0
  12. package/dist/pendingTransactions/pendingTransactions.d.ts +113 -9
  13. package/dist/pendingTransactions/pendingTransactions.js +147 -30
  14. package/dist/pendingTransactions/pendingTransactionsService.d.ts +25 -9
  15. package/dist/pendingTransactions/pendingTransactionsService.js +33 -21
  16. package/dist/proving/index.d.ts +2 -0
  17. package/dist/proving/index.js +2 -0
  18. package/dist/proving/provingService.d.ts +184 -15
  19. package/dist/proving/provingService.js +114 -12
  20. package/dist/proving/v8ProvingService.d.ts +53 -0
  21. package/dist/proving/v8ProvingService.js +71 -0
  22. package/dist/proving/versionedProving.d.ts +42 -0
  23. package/dist/proving/versionedProving.js +103 -0
  24. package/dist/signatures/index.d.ts +2 -0
  25. package/dist/signatures/index.js +14 -0
  26. package/dist/signatures/signing.d.ts +37 -0
  27. package/dist/signatures/signing.js +13 -0
  28. package/dist/signatures/v8Signatures.d.ts +54 -0
  29. package/dist/signatures/v8Signatures.js +62 -0
  30. package/dist/simulation/ForkSimulator.d.ts +114 -0
  31. package/dist/simulation/ForkSimulator.js +209 -0
  32. package/dist/simulation/LedgerTranslation.d.ts +53 -0
  33. package/dist/simulation/LedgerTranslation.js +56 -0
  34. package/dist/simulation/core/VersionTimeline.d.ts +54 -0
  35. package/dist/simulation/core/VersionTimeline.js +56 -0
  36. package/dist/simulation/core/blocks.d.ts +38 -0
  37. package/dist/simulation/core/blocks.js +52 -0
  38. package/dist/simulation/core/index.d.ts +13 -0
  39. package/dist/simulation/core/index.js +25 -0
  40. package/dist/simulation/core/strictness.d.ts +29 -0
  41. package/dist/simulation/core/strictness.js +39 -0
  42. package/dist/simulation/index.d.ts +22 -2
  43. package/dist/simulation/index.js +25 -14
  44. package/dist/simulation/v8/Simulator.d.ts +231 -0
  45. package/dist/simulation/v8/Simulator.js +503 -0
  46. package/dist/simulation/{SimulatorState.d.ts → v8/SimulatorState.d.ts} +31 -44
  47. package/dist/simulation/v8/SimulatorState.js +290 -0
  48. package/dist/simulation/v8/index.d.ts +2 -0
  49. package/dist/simulation/v8/index.js +26 -0
  50. package/dist/simulation/{Simulator.d.ts → v9/Simulator.d.ts} +57 -6
  51. package/dist/simulation/{Simulator.js → v9/Simulator.js} +68 -18
  52. package/dist/simulation/v9/SimulatorState.d.ts +336 -0
  53. package/dist/simulation/{SimulatorState.js → v9/SimulatorState.js} +34 -67
  54. package/dist/simulation/v9/index.d.ts +2 -0
  55. package/dist/simulation/v9/index.js +26 -0
  56. package/dist/submission/submissionService.d.ts +2 -1
  57. package/dist/submission/submissionService.js +1 -1
  58. package/dist/validation/blockData.d.ts +42 -2
  59. package/dist/validation/blockData.js +55 -8
  60. package/dist/validation/index.d.ts +2 -0
  61. package/dist/validation/index.js +2 -0
  62. package/dist/validation/v8ValidationService.d.ts +29 -0
  63. package/dist/validation/v8ValidationService.js +48 -0
  64. package/dist/validation/validationService.d.ts +132 -17
  65. package/dist/validation/validationService.js +88 -42
  66. package/dist/validation/versionedValidation.d.ts +46 -0
  67. package/dist/validation/versionedValidation.js +55 -0
  68. package/package.json +28 -14
@@ -0,0 +1,336 @@
1
+ /**
2
+ * SimulatorState types and pure functions for state manipulation.
3
+ *
4
+ * This module contains the core data types and pure functions for working with simulator state. All functions are
5
+ * synchronous and side-effect free.
6
+ */
7
+ import { Either, type Stream, Array as EArray } from 'effect';
8
+ import { LedgerState, WellFormedStrictness, type TransactionResult, type ProofErasedTransaction, type SyntheticCost, type RawTokenType, type ZswapSecretKeys, type UserAddress, type SignatureVerifyingKey } from '@midnightntwrk/ledger-v9';
9
+ import { LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
10
+ import { type NetworkId, ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
11
+ import { type BlockContext, type ScheduledFork, type StrictnessConfig } from '../core/index.js';
12
+ export { blockHash, defaultStrictness, genesisStrictness, getProtocolVersion, nextBlockContextFromBlock, protocolVersionAt, scheduleFork, setProtocolVersion, type BlockContext, type ScheduledFork, type StrictnessConfig, } from '../core/index.js';
13
+ /** A transaction included in a block with its execution result. */
14
+ export type BlockTransaction = Readonly<{
15
+ /** The transaction that was executed */
16
+ tx: ProofErasedTransaction;
17
+ /** The result of executing the transaction */
18
+ result: TransactionResult;
19
+ }>;
20
+ /** A produced block containing transactions and metadata. */
21
+ export type Block = Readonly<{
22
+ /** Block number (height) */
23
+ number: bigint;
24
+ /** Block hash */
25
+ hash: string;
26
+ /** Block timestamp */
27
+ timestamp: Date;
28
+ /** Transactions in this block, ordered by execution */
29
+ transactions: readonly BlockTransaction[];
30
+ /**
31
+ * Protocol version this block was produced under. Stamped at production time and never revised afterwards, so the
32
+ * chain's history records which version each block belongs to — exactly what a syncing wallet reads to decide which
33
+ * codec applies and when to migrate.
34
+ */
35
+ protocolVersion: ProtocolVersion.ProtocolVersion;
36
+ }>;
37
+ /**
38
+ * Pending transaction waiting for block production. Strictness is optional - if not specified, block producer assigns
39
+ * default when creating block.
40
+ */
41
+ export type PendingTransaction = Readonly<{
42
+ tx: ProofErasedTransaction;
43
+ /** Optional per-transaction strictness. If not specified, block producer assigns default. */
44
+ strictness?: WellFormedStrictness;
45
+ }>;
46
+ /**
47
+ * Transaction ready for block production with strictness assigned. Block producer ensures all transactions have
48
+ * strictness before block creation.
49
+ */
50
+ export type ReadyTransaction = Readonly<{
51
+ tx: ProofErasedTransaction;
52
+ /** Strictness for validation (assigned by block producer if not specified on pending tx). */
53
+ strictness: WellFormedStrictness;
54
+ }>;
55
+ /** Simulator state containing the ledger, block history, and pending mempool. */
56
+ export type SimulatorState = Readonly<{
57
+ networkId: NetworkId.NetworkId;
58
+ ledger: LedgerState;
59
+ /** All produced blocks, ordered by block number */
60
+ blocks: EArray.NonEmptyArray<Block>;
61
+ /** Pending transactions waiting for block production */
62
+ mempool: readonly PendingTransaction[];
63
+ /** Current simulator time (independent of block numbers) */
64
+ currentTime: Date;
65
+ /** Protocol version the chain is currently on — stamped onto blocks as they are produced */
66
+ protocolVersion: ProtocolVersion.ProtocolVersion;
67
+ /** Version activations scheduled at block heights, applied when those heights are produced */
68
+ scheduledForks: readonly ScheduledFork[];
69
+ }>;
70
+ /** Result of a successful block production. */
71
+ export type BlockInfo = Readonly<{
72
+ blockNumber: bigint;
73
+ blockHash: string;
74
+ }>;
75
+ /**
76
+ * Request to produce a block with specific transactions, fullness, and optional strictness override. This mimics how
77
+ * real nodes work - selecting which transactions to include and how to validate them.
78
+ *
79
+ * The block producer can optionally specify a strictness that overrides per-transaction strictness. This enables
80
+ * patterns like:
81
+ *
82
+ * - Enforcing balancing for all blocks after genesis
83
+ * - Using a decorator pattern to modify strictness behavior
84
+ * - Testing specific validation scenarios
85
+ */
86
+ export type BlockProductionRequest = Readonly<{
87
+ /** Transactions to include in this block with strictness assigned */
88
+ transactions: readonly ReadyTransaction[];
89
+ /** Block fullness (0-1) for fee calculation */
90
+ fullness: number;
91
+ }>;
92
+ /**
93
+ * A block producer is a stream transformer that decides when blocks should be produced.
94
+ *
95
+ * It receives a stream of simulator state changes and transforms it into a stream of block production requests. Each
96
+ * request specifies which transactions to include and the block fullness for fee calculation.
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * // Custom producer: produce block when mempool has 5+ transactions
101
+ * const batchedProducer: BlockProducer = (states) =>
102
+ * states.pipe(
103
+ * Stream.filter((s) => s.mempool.length >= 5),
104
+ * Stream.map((s) => ({
105
+ * transactions: [...s.mempool],
106
+ * fullness: 0.5,
107
+ * }))
108
+ * );
109
+ * ```;
110
+ */
111
+ export type BlockProducer = (states: Stream.Stream<SimulatorState>) => Stream.Stream<BlockProductionRequest>;
112
+ /** Fullness specification: static number or callback based on state. */
113
+ export type FullnessSpec = number | ((state: SimulatorState) => number);
114
+ /**
115
+ * Genesis mint specification for shielded tokens.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const mint: ShieldedGenesisMint = {
120
+ * type: 'shielded',
121
+ * tokenType: ledger.shieldedToken().raw,
122
+ * amount: 1000n,
123
+ * recipient: secretKeys,
124
+ * };
125
+ * ```;
126
+ */
127
+ export type ShieldedGenesisMint = Readonly<{
128
+ type: 'shielded';
129
+ tokenType: RawTokenType;
130
+ amount: bigint;
131
+ recipient: ZswapSecretKeys;
132
+ }>;
133
+ /**
134
+ * Genesis mint specification for unshielded tokens.
135
+ *
136
+ * For **custom tokens**: Minted directly from nothing (enforceBalancing disabled).
137
+ *
138
+ * For **Night tokens** (native token): Requires `verifyingKey` field. Night cannot be minted from nothing due to supply
139
+ * invariant, so the reward/claim mechanism is used internally. Night is auto-detected by comparing `tokenType` with
140
+ * `ledger.nativeToken().raw`.
141
+ *
142
+ * Note: Night claims have a minimum amount requirement (~14077). Use larger amounts to ensure the claim transaction
143
+ * succeeds.
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * // Custom unshielded token
148
+ * const customMint: UnshieldedGenesisMint = {
149
+ * type: 'unshielded',
150
+ * tokenType: customToken,
151
+ * amount: 1000n,
152
+ * recipient: userAddress,
153
+ * };
154
+ *
155
+ * // Night token (native token) - requires verifyingKey
156
+ * const nightMint: UnshieldedGenesisMint = {
157
+ * type: 'unshielded',
158
+ * tokenType: ledger.nativeToken().raw,
159
+ * amount: 1_000_000n, // Must exceed minimum claim amount (~14077)
160
+ * recipient: userAddress,
161
+ * verifyingKey: signatureVerifyingKey,
162
+ * };
163
+ * ```;
164
+ */
165
+ export type UnshieldedGenesisMint = Readonly<{
166
+ type: 'unshielded';
167
+ tokenType: RawTokenType;
168
+ amount: bigint;
169
+ recipient: UserAddress;
170
+ /** Required for Night tokens (native token). Used for the claim transaction signature. */
171
+ verifyingKey?: SignatureVerifyingKey;
172
+ }>;
173
+ /**
174
+ * Genesis mint specification for initializing the simulator with pre-funded accounts.
175
+ *
176
+ * Uses a tagged union pattern consistent with the facade API:
177
+ *
178
+ * - **Shielded**: `{ type: 'shielded', tokenType, amount, recipient: ZswapSecretKeys }`
179
+ * - **Unshielded**: `{ type: 'unshielded', tokenType, amount, recipient, verifyingKey? }`
180
+ *
181
+ * - Custom tokens: minted directly (verifyingKey not needed)
182
+ * - Night tokens: auto-detected by tokenType, uses reward/claim mechanism (verifyingKey required)
183
+ */
184
+ export type GenesisMint = ShieldedGenesisMint | UnshieldedGenesisMint;
185
+ /**
186
+ * Assign strictness to a pending transaction, creating a ready transaction. If the pending transaction already has
187
+ * strictness, use it; otherwise use the provided default.
188
+ */
189
+ export declare const assignStrictness: (pendingTx: PendingTransaction, defaultStrictness: WellFormedStrictness) => ReadyTransaction;
190
+ /**
191
+ * Assign strictness to all pending transactions, creating ready transactions. Transactions with existing strictness
192
+ * keep their strictness; others get the default.
193
+ */
194
+ export declare const assignStrictnessToAll: (transactions: readonly PendingTransaction[], defaultStrictness: WellFormedStrictness) => readonly ReadyTransaction[];
195
+ /** Get the last produced block, or undefined if no blocks yet. */
196
+ export declare const getLastBlock: (state: SimulatorState) => Block;
197
+ /** Get the current block number (height of the last block, or 0 if no blocks). */
198
+ export declare const getCurrentBlockNumber: (state: SimulatorState) => bigint;
199
+ /** Get a block by its number. */
200
+ export declare const getBlockByNumber: {
201
+ (number: bigint): (state: SimulatorState) => Block | undefined;
202
+ (state: SimulatorState, number: bigint): Block | undefined;
203
+ };
204
+ /** Get all transaction results from the last block. */
205
+ export declare const getLastBlockResults: (state: SimulatorState) => readonly TransactionResult[];
206
+ /** Get all events from the last block (flattened from all transactions). */
207
+ export declare const getLastBlockEvents: (state: SimulatorState) => readonly TransactionResult["events"][number][];
208
+ /**
209
+ * Get all events from blocks with number >= fromBlockNumber. Returns events ordered by block number, with each block's
210
+ * transactions flattened.
211
+ *
212
+ * Use this with the wallet's next-to-process index: `appliedIndex` after processing should be set to `lastBlockNumber +
213
+ * 1`, not `lastBlockNumber`.
214
+ */
215
+ export declare const getBlockEventsFrom: {
216
+ (fromBlockNumber: bigint): (state: SimulatorState) => readonly TransactionResult['events'][number][];
217
+ (state: SimulatorState, fromBlockNumber: bigint): readonly TransactionResult['events'][number][];
218
+ };
219
+ /**
220
+ * @deprecated Use getBlockEventsFrom instead with proper appliedIndex semantics Get all events from blocks with number
221
+ *
222
+ * > AfterBlockNumber.
223
+ */
224
+ export declare const getBlockEventsSince: {
225
+ (afterBlockNumber: bigint): (state: SimulatorState) => readonly TransactionResult['events'][number][];
226
+ (state: SimulatorState, afterBlockNumber: bigint): readonly TransactionResult['events'][number][];
227
+ };
228
+ /** Check if there are pending transactions in the mempool. */
229
+ export declare const hasPendingTransactions: (state: SimulatorState) => boolean;
230
+ /** Get the current simulator time. */
231
+ export declare const getCurrentTime: (state: SimulatorState) => Date;
232
+ /** Resolve fullness from spec and state. */
233
+ export declare const resolveFullness: (spec: FullnessSpec, state: SimulatorState) => number;
234
+ /** Create a block production request that includes all mempool transactions. */
235
+ export declare const allMempoolTransactions: (state: SimulatorState, fullness: number, defaultStrictness: WellFormedStrictness) => BlockProductionRequest;
236
+ /**
237
+ * Create a blank initial state.
238
+ *
239
+ * @param networkId - Network identifier
240
+ * @param options - Optional genesis parameters
241
+ * @param options.protocolVersion - Version the chain starts on (defaults to the minimum supported version)
242
+ * @param options.genesisBlockNumber - Height of the genesis block (defaults to 0; a ledger-v9 chain continues numbering
243
+ * from the fork height instead)
244
+ * @param options.genesisTime - Timestamp of the genesis block (defaults to the epoch)
245
+ */
246
+ export declare const blankState: (networkId: NetworkId.NetworkId, options?: {
247
+ protocolVersion?: ProtocolVersion.ProtocolVersion;
248
+ genesisBlockNumber?: bigint;
249
+ genesisTime?: Date;
250
+ }) => Promise<SimulatorState>;
251
+ /** Add a pending transaction to the mempool. */
252
+ export declare const addToMempool: (state: SimulatorState, pendingTx: PendingTransaction) => SimulatorState;
253
+ /** Remove transactions from the mempool. */
254
+ export declare const removeFromMempool: (state: SimulatorState, transactions: readonly ReadyTransaction[]) => SimulatorState;
255
+ /** Advance the simulator time by the given number of seconds. */
256
+ export declare const advanceTime: (state: SimulatorState, seconds: bigint) => SimulatorState;
257
+ /** Update the ledger state. */
258
+ export declare const updateLedger: (state: SimulatorState, ledger: LedgerState) => SimulatorState;
259
+ /** Append a block to the state and update time. */
260
+ export declare const appendBlock: (state: SimulatorState, block: Block, newLedger: LedgerState) => SimulatorState;
261
+ /**
262
+ * Pure state transition: apply a transaction to the simulator state. Returns Either with the new state or an error.
263
+ *
264
+ * @param state - Current simulator state
265
+ * @param tx - Transaction to apply
266
+ * @param strictness - Well-formedness strictness options
267
+ * @param blockContext - Block context for the transaction
268
+ * @param options - Optional parameters
269
+ * @param options.blockNumber - Override block number (defaults to last block + 1)
270
+ * @param options.blockFullness - Override detailed block fullness (SyntheticCost)
271
+ * @param options.overallBlockFullness - Override overall block fullness (0-1 value)
272
+ */
273
+ export declare const applyTransaction: (state: SimulatorState, tx: ProofErasedTransaction, strictness: WellFormedStrictness, blockContext: BlockContext, options?: {
274
+ blockNumber?: bigint;
275
+ blockFullness?: SyntheticCost;
276
+ overallBlockFullness?: number;
277
+ }) => Either.Either<[Block, SimulatorState], LedgerOps.LedgerError>;
278
+ /** Result of processing a single transaction. */
279
+ export type TransactionProcessingResult = Readonly<{
280
+ tx: ProofErasedTransaction;
281
+ result: TransactionResult;
282
+ newLedger: LedgerState;
283
+ }>;
284
+ /**
285
+ * Process a single pending transaction against the latest ledger state. Returns Either with the processing result or an
286
+ * error.
287
+ *
288
+ * @param ledger - The ledger state to process against
289
+ * @param readyTx - Transaction to process
290
+ * @param blockTime - Block timestamp
291
+ * @param blockContext - Block context
292
+ * @param minFullness - Minimum block fullness to use
293
+ */
294
+ export declare const processTransaction: (ledger: LedgerState, readyTx: ReadyTransaction, blockTime: Date, blockContext: BlockContext, minFullness: number) => Either.Either<TransactionProcessingResult, LedgerOps.LedgerError>;
295
+ /**
296
+ * Process multiple transactions in sequence, accumulating results. Returns Either with all results and final ledger, or
297
+ * first error. Each transaction uses its assigned strictness (from ReadyTransaction).
298
+ *
299
+ * @param ledger - Initial ledger state
300
+ * @param transactions - Transactions to process (each with assigned strictness)
301
+ * @param blockTime - Block timestamp
302
+ * @param blockContext - Block context
303
+ * @param fullness - Block fullness (0-1)
304
+ */
305
+ export declare const processTransactions: (ledger: LedgerState, transactions: readonly ReadyTransaction[], blockTime: Date, blockContext: BlockContext, fullness: number) => Either.Either<{
306
+ blockTransactions: readonly BlockTransaction[];
307
+ finalLedger: LedgerState;
308
+ }, LedgerOps.LedgerError>;
309
+ /**
310
+ * Create a block from processed transactions and update state. Pure function that takes pre-computed block hash.
311
+ *
312
+ * @param state - Current simulator state
313
+ * @param blockTransactions - Processed transactions to include
314
+ * @param blockHash - Pre-computed block hash
315
+ * @param blockTime - Block timestamp
316
+ * @param newLedger - New ledger state after processing transactions
317
+ * @param processedTxs - Ready transactions to remove from mempool
318
+ */
319
+ export declare const createBlock: (state: SimulatorState, blockTransactions: readonly BlockTransaction[], blockHashValue: string, blockTime: Date, newLedger: LedgerState, processedTxs: readonly ReadyTransaction[]) => [Block, SimulatorState];
320
+ /**
321
+ * Create an empty block (no transactions) and update state.
322
+ *
323
+ * @param state - Current simulator state
324
+ * @param blockHashValue - Pre-computed block hash
325
+ * @param blockTime - Block timestamp
326
+ * @param processedTxs - Original pending transactions to remove from mempool (if any)
327
+ */
328
+ export declare const createEmptyBlock: (state: SimulatorState, blockHashValue: string, blockTime: Date, processedTxs?: readonly ReadyTransaction[]) => [Block, SimulatorState];
329
+ /**
330
+ * Create a WellFormedStrictness instance with configurable options. All options default to false for maximum testing
331
+ * flexibility.
332
+ *
333
+ * Note: WellFormedStrictness is a class from the ledger library that requires mutation to configure. This is
334
+ * unavoidable given the external API design.
335
+ */
336
+ export declare const createStrictness: (config?: StrictnessConfig) => WellFormedStrictness;
@@ -19,33 +19,10 @@
19
19
  import { Either, Function as EFunction, Array as EArray } from 'effect';
20
20
  import { LedgerState, WellFormedStrictness, TransactionContext, } from '@midnightntwrk/ledger-v9';
21
21
  import { DateOps, LedgerOps } from '@midnight-ntwrk/wallet-sdk-utilities';
22
- /**
23
- * Default strictness for post-genesis blocks.
24
- *
25
- * In a realistic simulation:
26
- *
27
- * - Signatures should be verified (verifySignatures: true)
28
- * - Proofs cannot be verified because they're erased (verifyNativeProofs/verifyContractProofs: false)
29
- * - Limits should be enforced (enforceLimits: true)
30
- * - Balancing must be enforced (enforceBalancing: true) - transactions must pay fees
31
- *
32
- * Note: Genesis blocks typically disable all strictness to allow initial token distribution.
33
- */
34
- export const defaultStrictness = {
35
- enforceBalancing: true,
36
- verifyNativeProofs: false,
37
- verifyContractProofs: false,
38
- enforceLimits: true,
39
- verifySignatures: true,
40
- };
41
- /** Strictness for genesis blocks - all checks disabled to allow initial token distribution. */
42
- export const genesisStrictness = {
43
- enforceBalancing: false,
44
- verifyNativeProofs: false,
45
- verifyContractProofs: false,
46
- enforceLimits: false,
47
- verifySignatures: false,
48
- };
22
+ import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
23
+ import { blockHash, protocolVersionAt, } from '../core/index.js';
24
+ // Version-agnostic simulator internals, re-exported so each version's barrel presents one complete surface.
25
+ export { blockHash, defaultStrictness, genesisStrictness, getProtocolVersion, nextBlockContextFromBlock, protocolVersionAt, scheduleFork, setProtocolVersion, } from '../core/index.js';
49
26
  /**
50
27
  * Assign strictness to a pending transaction, creating a ready transaction. If the pending transaction already has
51
28
  * strictness, use it; otherwise use the provided default.
@@ -104,20 +81,35 @@ export const allMempoolTransactions = (state, fullness, defaultStrictness) => ({
104
81
  transactions: assignStrictnessToAll(state.mempool, defaultStrictness),
105
82
  fullness,
106
83
  });
107
- /** Create a blank initial state. */
108
- export const blankState = async (networkId) => {
84
+ /**
85
+ * Create a blank initial state.
86
+ *
87
+ * @param networkId - Network identifier
88
+ * @param options - Optional genesis parameters
89
+ * @param options.protocolVersion - Version the chain starts on (defaults to the minimum supported version)
90
+ * @param options.genesisBlockNumber - Height of the genesis block (defaults to 0; a ledger-v9 chain continues numbering
91
+ * from the fork height instead)
92
+ * @param options.genesisTime - Timestamp of the genesis block (defaults to the epoch)
93
+ */
94
+ export const blankState = async (networkId, options) => {
95
+ const protocolVersion = options?.protocolVersion ?? ProtocolVersion.MinSupportedVersion;
96
+ const genesisBlockNumber = options?.genesisBlockNumber ?? 0n;
97
+ const genesisTime = options?.genesisTime ?? new Date(0);
109
98
  const blankGenesis = {
110
- number: 0n,
111
- hash: await blockHash(0n),
112
- timestamp: new Date(0),
99
+ number: genesisBlockNumber,
100
+ hash: await blockHash(genesisBlockNumber),
101
+ timestamp: genesisTime,
113
102
  transactions: [],
103
+ protocolVersion,
114
104
  };
115
105
  return {
116
106
  networkId,
117
107
  ledger: LedgerState.blank(networkId),
118
108
  blocks: [blankGenesis],
119
109
  mempool: [],
120
- currentTime: new Date(0),
110
+ currentTime: genesisTime,
111
+ protocolVersion,
112
+ scheduledForks: [],
121
113
  };
122
114
  };
123
115
  /** Add a pending transaction to the mempool. */
@@ -172,6 +164,7 @@ export const applyTransaction = (state, tx, strictness, blockContext, options) =
172
164
  const computedBlockFullness = options?.overallBlockFullness ??
173
165
  Math.max(detailedBlockFullness.readTime, detailedBlockFullness.computeTime, detailedBlockFullness.blockUsage, detailedBlockFullness.bytesWritten, detailedBlockFullness.bytesChurned);
174
166
  const blockNumber = options?.blockNumber ?? getCurrentBlockNumber(state) + 1n;
167
+ const protocolVersion = protocolVersionAt(state, blockNumber);
175
168
  const blockTime = state.currentTime;
176
169
  const verifiedTransaction = tx.wellFormed(state.ledger, strictness, blockTime);
177
170
  const transactionContext = new TransactionContext(state.ledger, blockContext);
@@ -181,20 +174,22 @@ export const applyTransaction = (state, tx, strictness, blockContext, options) =
181
174
  hash: blockContext.parentBlockHash,
182
175
  timestamp: blockTime,
183
176
  transactions: [{ tx, result: txResult }],
177
+ protocolVersion,
184
178
  };
185
179
  const newState = {
186
180
  ...state,
187
181
  ledger: newLedgerState.postBlockUpdate(blockTime, detailedBlockFullness, computedBlockFullness),
188
182
  blocks: [...state.blocks, newBlock],
183
+ protocolVersion,
189
184
  };
190
185
  return [newBlock, newState];
191
186
  });
192
187
  };
193
188
  /**
194
- * Process a single pending transaction against the current ledger. Returns Either with the processing result or an
189
+ * Process a single pending transaction against the latest ledger state. Returns Either with the processing result or an
195
190
  * error.
196
191
  *
197
- * @param ledger - Current ledger state
192
+ * @param ledger - The ledger state to process against
198
193
  * @param readyTx - Transaction to process
199
194
  * @param blockTime - Block timestamp
200
195
  * @param blockContext - Block context
@@ -243,11 +238,14 @@ export const processTransactions = (ledger, transactions, blockTime, blockContex
243
238
  */
244
239
  export const createBlock = (state, blockTransactions, blockHashValue, blockTime, newLedger, processedTxs) => {
245
240
  const nextBlockNumber = getCurrentBlockNumber(state) + 1n;
241
+ // Resolved once, at production time: the block and the chain's current version cannot disagree.
242
+ const protocolVersion = protocolVersionAt(state, nextBlockNumber);
246
243
  const block = {
247
244
  number: nextBlockNumber,
248
245
  hash: blockHashValue,
249
246
  timestamp: blockTime,
250
247
  transactions: blockTransactions,
248
+ protocolVersion,
251
249
  };
252
250
  const txsToRemove = new Set(processedTxs.map((t) => t.tx));
253
251
  const newState = {
@@ -256,6 +254,7 @@ export const createBlock = (state, blockTransactions, blockHashValue, blockTime,
256
254
  blocks: [...state.blocks, block],
257
255
  mempool: state.mempool.filter((pending) => !txsToRemove.has(pending.tx)),
258
256
  currentTime: blockTime,
257
+ protocolVersion,
259
258
  };
260
259
  return [block, newState];
261
260
  };
@@ -289,35 +288,3 @@ export const createStrictness = (config = {}) => {
289
288
  strictness.verifySignatures = config.verifySignatures ?? false;
290
289
  return strictness;
291
290
  };
292
- /**
293
- * Compute block hash from block number. Uses a deterministic hash based on block number for easy recomputation.
294
- *
295
- * @param blockNumber - The block number to compute hash for
296
- * @returns A deterministic 64-character hex hash
297
- */
298
- export const blockHash = async (blockNumber) => {
299
- const input = `block-${blockNumber.toString()}`;
300
- const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(input));
301
- const { Encoding } = await import('effect');
302
- return Encoding.encodeHex(new Uint8Array(hashBuffer));
303
- };
304
- /**
305
- * Create the next block context from the previous block.
306
- *
307
- * @param previousBlock - The previous block (or undefined for genesis)
308
- * @param blockTime - The timestamp for the new block
309
- * @returns A BlockContext suitable for transaction processing
310
- */
311
- export const nextBlockContextFromBlock = async (previousBlock, blockTime) => {
312
- const nextBlockNumber = previousBlock !== undefined ? previousBlock.number + 1n : 0n;
313
- const hash = await blockHash(nextBlockNumber);
314
- const blockSeconds = DateOps.dateToSeconds(blockTime);
315
- const previousSeconds = previousBlock !== undefined ? DateOps.dateToSeconds(previousBlock.timestamp) : blockSeconds - 1n;
316
- const timeSinceLastBlock = blockSeconds - previousSeconds;
317
- return {
318
- parentBlockHash: hash,
319
- secondsSinceEpoch: blockSeconds,
320
- secondsSinceEpochErr: 1, // Clock error tolerance in seconds (reasonable default for simulator)
321
- lastBlockTime: timeSinceLastBlock > 0n ? timeSinceLastBlock : 1n,
322
- };
323
- };
@@ -0,0 +1,2 @@
1
+ export { getLastBlock, getCurrentBlockNumber, getCurrentTime, getProtocolVersion, protocolVersionAt, getBlockByNumber, getLastBlockResults, getLastBlockEvents, getBlockEventsFrom, getBlockEventsSince, hasPendingTransactions, resolveFullness, allMempoolTransactions, blankState, addToMempool, removeFromMempool, advanceTime, updateLedger, appendBlock, applyTransaction, setProtocolVersion, scheduleFork, processTransaction, processTransactions, createBlock, createEmptyBlock, type TransactionProcessingResult, createStrictness, blockHash, assignStrictness, assignStrictnessToAll, defaultStrictness, genesisStrictness, type SimulatorState, type Block, type BlockTransaction, type BlockInfo, type PendingTransaction, type ReadyTransaction, type BlockProductionRequest, type BlockProducer, type FullnessSpec, type GenesisMint, type ScheduledFork, type StrictnessConfig, } from './SimulatorState.js';
2
+ export { Simulator, immediateBlockProducer, type SimulatorConfig } from './Simulator.js';
@@ -0,0 +1,26 @@
1
+ // This file is part of MIDNIGHT-WALLET-SDK.
2
+ // Copyright (C) Midnight Foundation
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // You may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ // Re-export everything from SimulatorState
14
+ export {
15
+ // State accessor functions (composable with simulator.query())
16
+ getLastBlock, getCurrentBlockNumber, getCurrentTime, getProtocolVersion, protocolVersionAt, getBlockByNumber, getLastBlockResults, getLastBlockEvents, getBlockEventsFrom, getBlockEventsSince, hasPendingTransactions,
17
+ // State transformation functions
18
+ resolveFullness, allMempoolTransactions, blankState, addToMempool, removeFromMempool, advanceTime, updateLedger, appendBlock, applyTransaction, setProtocolVersion, scheduleFork,
19
+ // Block production functions
20
+ processTransaction, processTransactions, createBlock, createEmptyBlock,
21
+ // Helper functions
22
+ createStrictness, blockHash, assignStrictness, assignStrictnessToAll,
23
+ // Strictness constants
24
+ defaultStrictness, genesisStrictness, } from './SimulatorState.js';
25
+ // Re-export from Simulator
26
+ export { Simulator, immediateBlockProducer } from './Simulator.js';
@@ -1,7 +1,7 @@
1
1
  import { Effect } from 'effect';
2
2
  import { SubmissionEvent as SubmissionEventImported } from '@midnight-ntwrk/wallet-sdk-node-client/effect';
3
3
  import { type FinalizedTransaction } from '@midnightntwrk/ledger-v9';
4
- import { type SimulatorState } from '../simulation/Simulator.js';
4
+ import { type SimulatorState } from '../simulation/v9/Simulator.js';
5
5
  export declare const SubmissionEvent: typeof SubmissionEventImported;
6
6
  export type SubmissionEvent = SubmissionEventImported.SubmissionEvent;
7
7
  export declare namespace SubmissionEventCases {
@@ -44,6 +44,7 @@ export type DefaultSubmissionConfiguration = {
44
44
  };
45
45
  export declare const makeDefaultSubmissionServiceEffect: <TTransaction extends {
46
46
  serialize: () => Uint8Array;
47
+ toString: () => string;
47
48
  } = FinalizedTransaction>(config: DefaultSubmissionConfiguration) => SubmissionServiceEffect<TTransaction>;
48
49
  export declare const makeDefaultSubmissionService: <TTransaction extends {
49
50
  serialize: () => Uint8Array;
@@ -13,7 +13,7 @@
13
13
  import { Data, Deferred, Effect, Encoding, Exit, pipe, Scope } from 'effect';
14
14
  import { NodeClient, PolkadotNodeClient, SubmissionEvent as SubmissionEventImported, } from '@midnight-ntwrk/wallet-sdk-node-client/effect';
15
15
  import { SerializedTransaction } from '@midnight-ntwrk/wallet-sdk-abstractions';
16
- import { getLastBlock } from '../simulation/Simulator.js';
16
+ import { getLastBlock } from '../simulation/v9/Simulator.js';
17
17
  export const SubmissionEvent = SubmissionEventImported;
18
18
  export class SubmissionError extends Data.TaggedError('SubmissionError') {
19
19
  }
@@ -1,11 +1,51 @@
1
+ import { ProtocolVersion } from '@midnight-ntwrk/wallet-sdk-abstractions';
2
+ import { Either } from 'effect';
3
+ import { LedgerParametersCodec } from '../codecs/index.js';
1
4
  import { type Simulator } from '../simulation/index.js';
2
- import type { BlockData } from './validationService.js';
3
- export type BlockDataFetcher = () => Promise<BlockData>;
5
+ import type { AnyLedgerParameters, BlockData } from './validationService.js';
6
+ export type BlockDataFetcher = () => Promise<BlockData<AnyLedgerParameters>>;
7
+ /**
8
+ * The ledger parameters codecs validation reads blocks with, split at the version the chain forks at.
9
+ *
10
+ * @remarks
11
+ * A block's parameters are bytes of whichever ledger version produced the block, and the version the indexer reports
12
+ * the block under is what says which. Below the fork version they are read with ledger-v8's deserializer and from it
13
+ * with the current one, so that the object handed to a validator is always one its own `LedgerState` accepts.
14
+ *
15
+ * Nothing in the resulting type distinguishes the two: the ledger versions' `LedgerParameters` are structurally
16
+ * identical, so {@link AnyLedgerParameters} is a statement of intent rather than something the compiler enforces. The
17
+ * distinction is nominal at run time — the classes differ, and each ledger's WASM boundary rejects the other's —
18
+ * which is why the routing has to be right rather than merely well-typed.
19
+ * @param forkVersion The protocol version at which the chain hands over to the ledger-v9.
20
+ * @returns The registry blocks are read with.
21
+ */
22
+ export declare const defaultLedgerParametersCodecs: (forkVersion: ProtocolVersion.ProtocolVersion) => LedgerParametersCodec.LedgerParametersCodecs<AnyLedgerParameters>;
4
23
  export type DefaultBlockDataFetcherConfiguration = {
5
24
  indexerClientConnection: {
6
25
  indexerHttpUrl: string;
7
26
  };
27
+ /** Where each ledger version begins on this chain — see {@link ProtocolVersion.ForkSchedule}. */
28
+ forks: ProtocolVersion.ForkSchedule;
29
+ /** The ledger parameters codecs blocks are read with; defaults to {@link defaultLedgerParametersCodecs}. */
30
+ ledgerParametersCodecs?: LedgerParametersCodec.LedgerParametersCodecs<AnyLedgerParameters>;
8
31
  };
32
+ /** The block as the indexer serves it: parameters still hex, and the version that says how to read them. */
33
+ export type WireBlock = Readonly<{
34
+ hash: string;
35
+ height: number;
36
+ protocolVersion: number;
37
+ ledgerParameters: string;
38
+ timestamp: number;
39
+ }>;
40
+ /**
41
+ * Reads an indexer block into {@link BlockData}, decoding its ledger parameters with whichever registered codec claims
42
+ * the protocol version the block was reported under.
43
+ *
44
+ * @param codecs The ledger parameters codecs the caller is willing to read with.
45
+ * @param block The block as the indexer served it.
46
+ * @returns The block data, or the typed reason its parameters could not be read.
47
+ */
48
+ export declare const blockDataFrom: (codecs: LedgerParametersCodec.LedgerParametersCodecs<AnyLedgerParameters>, block: WireBlock) => Either.Either<BlockData<AnyLedgerParameters>, LedgerParametersCodec.LedgerParametersCodecError>;
9
49
  /**
10
50
  * Builds a `BlockDataFetcher` that queries the indexer over HTTP for the latest block.
11
51
  *