@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.
- package/README.md +27 -3
- package/dist/chainVersion/chainVersionProbe.d.ts +95 -0
- package/dist/chainVersion/chainVersionProbe.js +83 -0
- package/dist/chainVersion/index.d.ts +1 -0
- package/dist/chainVersion/index.js +13 -0
- package/dist/codecs/index.d.ts +1 -0
- package/dist/codecs/index.js +13 -0
- package/dist/codecs/ledgerParameters.d.ts +81 -0
- package/dist/codecs/ledgerParameters.js +63 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/pendingTransactions/pendingTransactions.d.ts +113 -9
- package/dist/pendingTransactions/pendingTransactions.js +147 -30
- package/dist/pendingTransactions/pendingTransactionsService.d.ts +25 -9
- package/dist/pendingTransactions/pendingTransactionsService.js +33 -21
- package/dist/proving/index.d.ts +2 -0
- package/dist/proving/index.js +2 -0
- package/dist/proving/provingService.d.ts +184 -15
- package/dist/proving/provingService.js +114 -12
- package/dist/proving/v8ProvingService.d.ts +53 -0
- package/dist/proving/v8ProvingService.js +71 -0
- package/dist/proving/versionedProving.d.ts +42 -0
- package/dist/proving/versionedProving.js +103 -0
- package/dist/signatures/index.d.ts +2 -0
- package/dist/signatures/index.js +14 -0
- package/dist/signatures/signing.d.ts +37 -0
- package/dist/signatures/signing.js +13 -0
- package/dist/signatures/v8Signatures.d.ts +54 -0
- package/dist/signatures/v8Signatures.js +62 -0
- package/dist/simulation/ForkSimulator.d.ts +114 -0
- package/dist/simulation/ForkSimulator.js +209 -0
- package/dist/simulation/LedgerTranslation.d.ts +53 -0
- package/dist/simulation/LedgerTranslation.js +56 -0
- package/dist/simulation/core/VersionTimeline.d.ts +54 -0
- package/dist/simulation/core/VersionTimeline.js +56 -0
- package/dist/simulation/core/blocks.d.ts +38 -0
- package/dist/simulation/core/blocks.js +52 -0
- package/dist/simulation/core/index.d.ts +13 -0
- package/dist/simulation/core/index.js +25 -0
- package/dist/simulation/core/strictness.d.ts +29 -0
- package/dist/simulation/core/strictness.js +39 -0
- package/dist/simulation/index.d.ts +22 -2
- package/dist/simulation/index.js +25 -14
- package/dist/simulation/v8/Simulator.d.ts +231 -0
- package/dist/simulation/v8/Simulator.js +503 -0
- package/dist/simulation/{SimulatorState.d.ts → v8/SimulatorState.d.ts} +31 -44
- package/dist/simulation/v8/SimulatorState.js +290 -0
- package/dist/simulation/v8/index.d.ts +2 -0
- package/dist/simulation/v8/index.js +26 -0
- package/dist/simulation/{Simulator.d.ts → v9/Simulator.d.ts} +57 -6
- package/dist/simulation/{Simulator.js → v9/Simulator.js} +68 -18
- package/dist/simulation/v9/SimulatorState.d.ts +336 -0
- package/dist/simulation/{SimulatorState.js → v9/SimulatorState.js} +34 -67
- package/dist/simulation/v9/index.d.ts +2 -0
- package/dist/simulation/v9/index.js +26 -0
- package/dist/submission/submissionService.d.ts +2 -1
- package/dist/submission/submissionService.js +1 -1
- package/dist/validation/blockData.d.ts +42 -2
- package/dist/validation/blockData.js +55 -8
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -0
- package/dist/validation/v8ValidationService.d.ts +29 -0
- package/dist/validation/v8ValidationService.js +48 -0
- package/dist/validation/validationService.d.ts +132 -17
- package/dist/validation/validationService.js +88 -42
- package/dist/validation/versionedValidation.d.ts +46 -0
- package/dist/validation/versionedValidation.js +55 -0
- 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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
/**
|
|
108
|
-
|
|
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:
|
|
111
|
-
hash: await blockHash(
|
|
112
|
-
timestamp:
|
|
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:
|
|
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
|
|
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 -
|
|
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
|
*
|