@solana/instruction-plans 3.0.0-canary-20250726063714 → 3.0.0-canary-20250808140800

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@
3
3
  var errors = require('@solana/errors');
4
4
  var transactionMessages = require('@solana/transaction-messages');
5
5
  var transactions = require('@solana/transactions');
6
+ var promises = require('@solana/promises');
6
7
 
7
8
  // src/instruction-plan.ts
8
9
  function parallelInstructionPlan(plans) {
@@ -115,12 +116,393 @@ function getReallocMessagePackerInstructionPlan({
115
116
  return getMessagePackerInstructionPlanFromInstructions(instructions);
116
117
  }
117
118
 
119
+ // src/transaction-plan-result.ts
120
+ function sequentialTransactionPlanResult(plans) {
121
+ return Object.freeze({ divisible: true, kind: "sequential", plans });
122
+ }
123
+ function nonDivisibleSequentialTransactionPlanResult(plans) {
124
+ return Object.freeze({ divisible: false, kind: "sequential", plans });
125
+ }
126
+ function parallelTransactionPlanResult(plans) {
127
+ return Object.freeze({ kind: "parallel", plans });
128
+ }
129
+ function successfulSingleTransactionPlanResult(transactionMessage, transaction, context) {
130
+ return Object.freeze({
131
+ kind: "single",
132
+ message: transactionMessage,
133
+ status: Object.freeze({ context: context ?? {}, kind: "successful", transaction })
134
+ });
135
+ }
136
+ function failedSingleTransactionPlanResult(transactionMessage, error) {
137
+ return Object.freeze({
138
+ kind: "single",
139
+ message: transactionMessage,
140
+ status: Object.freeze({ error, kind: "failed" })
141
+ });
142
+ }
143
+ function canceledSingleTransactionPlanResult(transactionMessage) {
144
+ return Object.freeze({
145
+ kind: "single",
146
+ message: transactionMessage,
147
+ status: Object.freeze({ kind: "canceled" })
148
+ });
149
+ }
150
+
151
+ // src/transaction-plan-executor.ts
152
+ function createTransactionPlanExecutor(config) {
153
+ return async (plan, { abortSignal } = {}) => {
154
+ const context = {
155
+ ...config,
156
+ abortSignal,
157
+ canceled: abortSignal?.aborted ?? false
158
+ };
159
+ const cancelHandler = () => {
160
+ context.canceled = true;
161
+ };
162
+ abortSignal?.addEventListener("abort", cancelHandler);
163
+ const transactionPlanResult = await traverse(plan, context);
164
+ abortSignal?.removeEventListener("abort", cancelHandler);
165
+ if (context.canceled) {
166
+ const abortReason = abortSignal?.aborted ? abortSignal.reason : void 0;
167
+ const context2 = { cause: findErrorFromTransactionPlanResult(transactionPlanResult) ?? abortReason };
168
+ Object.defineProperty(context2, "transactionPlanResult", {
169
+ configurable: false,
170
+ enumerable: false,
171
+ value: transactionPlanResult,
172
+ writable: false
173
+ });
174
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__FAILED_TO_EXECUTE_TRANSACTION_PLAN, context2);
175
+ }
176
+ return transactionPlanResult;
177
+ };
178
+ }
179
+ async function traverse(transactionPlan, context) {
180
+ const kind = transactionPlan.kind;
181
+ switch (kind) {
182
+ case "sequential":
183
+ return await traverseSequential(transactionPlan, context);
184
+ case "parallel":
185
+ return await traverseParallel(transactionPlan, context);
186
+ case "single":
187
+ return await traverseSingle(transactionPlan, context);
188
+ default:
189
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INVARIANT_VIOLATION__INVALID_TRANSACTION_PLAN_KIND, { kind });
190
+ }
191
+ }
192
+ async function traverseSequential(transactionPlan, context) {
193
+ const results = [];
194
+ for (const subPlan of transactionPlan.plans) {
195
+ const result = await traverse(subPlan, context);
196
+ results.push(result);
197
+ }
198
+ return transactionPlan.divisible ? sequentialTransactionPlanResult(results) : nonDivisibleSequentialTransactionPlanResult(results);
199
+ }
200
+ async function traverseParallel(transactionPlan, context) {
201
+ const results = await Promise.all(transactionPlan.plans.map((plan) => traverse(plan, context)));
202
+ return parallelTransactionPlanResult(results);
203
+ }
204
+ async function traverseSingle(transactionPlan, context) {
205
+ if (context.canceled) {
206
+ return canceledSingleTransactionPlanResult(transactionPlan.message);
207
+ }
208
+ try {
209
+ const result = await promises.getAbortablePromise(
210
+ context.executeTransactionMessage(transactionPlan.message, { abortSignal: context.abortSignal }),
211
+ context.abortSignal
212
+ );
213
+ return successfulSingleTransactionPlanResult(transactionPlan.message, result.transaction, result.context);
214
+ } catch (error) {
215
+ context.canceled = true;
216
+ return failedSingleTransactionPlanResult(transactionPlan.message, error);
217
+ }
218
+ }
219
+ function findErrorFromTransactionPlanResult(result) {
220
+ if (result.kind === "single") {
221
+ return result.status.kind === "failed" ? result.status.error : void 0;
222
+ }
223
+ for (const plan of result.plans) {
224
+ const error = findErrorFromTransactionPlanResult(plan);
225
+ if (error) {
226
+ return error;
227
+ }
228
+ }
229
+ }
230
+
231
+ // src/transaction-plan.ts
232
+ function parallelTransactionPlan(plans) {
233
+ return Object.freeze({ kind: "parallel", plans: parseSingleTransactionPlans(plans) });
234
+ }
235
+ function sequentialTransactionPlan(plans) {
236
+ return Object.freeze({ divisible: true, kind: "sequential", plans: parseSingleTransactionPlans(plans) });
237
+ }
238
+ function nonDivisibleSequentialTransactionPlan(plans) {
239
+ return Object.freeze({ divisible: false, kind: "sequential", plans: parseSingleTransactionPlans(plans) });
240
+ }
241
+ function singleTransactionPlan(transactionMessage) {
242
+ return Object.freeze({ kind: "single", message: transactionMessage });
243
+ }
244
+ function parseSingleTransactionPlans(plans) {
245
+ return plans.map((plan) => "kind" in plan ? plan : singleTransactionPlan(plan));
246
+ }
247
+ function getAllSingleTransactionPlans(transactionPlan) {
248
+ if (transactionPlan.kind === "single") {
249
+ return [transactionPlan];
250
+ }
251
+ return transactionPlan.plans.flatMap(getAllSingleTransactionPlans);
252
+ }
253
+ function createTransactionPlanner(config) {
254
+ return async (instructionPlan, { abortSignal } = {}) => {
255
+ const plan = await traverse2(instructionPlan, {
256
+ abortSignal,
257
+ createTransactionMessage: config.createTransactionMessage,
258
+ onTransactionMessageUpdated: config.onTransactionMessageUpdated ?? ((msg) => msg),
259
+ parent: null,
260
+ parentCandidates: []
261
+ });
262
+ if (!plan) {
263
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__EMPTY_INSTRUCTION_PLAN);
264
+ }
265
+ return freezeTransactionPlan(plan);
266
+ };
267
+ }
268
+ async function traverse2(instructionPlan, context) {
269
+ context.abortSignal?.throwIfAborted();
270
+ const kind = instructionPlan.kind;
271
+ switch (kind) {
272
+ case "sequential":
273
+ return await traverseSequential2(instructionPlan, context);
274
+ case "parallel":
275
+ return await traverseParallel2(instructionPlan, context);
276
+ case "single":
277
+ return await traverseSingle2(instructionPlan, context);
278
+ case "messagePacker":
279
+ return await traverseMessagePacker(instructionPlan, context);
280
+ default:
281
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INVARIANT_VIOLATION__INVALID_INSTRUCTION_PLAN_KIND, { kind });
282
+ }
283
+ }
284
+ async function traverseSequential2(instructionPlan, context) {
285
+ let candidate = null;
286
+ const mustEntirelyFitInParentCandidate = context.parent && (context.parent.kind === "parallel" || !instructionPlan.divisible);
287
+ if (mustEntirelyFitInParentCandidate) {
288
+ const candidate2 = await selectAndMutateCandidate(
289
+ context,
290
+ context.parentCandidates,
291
+ (message) => fitEntirePlanInsideMessage(instructionPlan, message)
292
+ );
293
+ if (candidate2) {
294
+ return null;
295
+ }
296
+ } else {
297
+ candidate = context.parentCandidates.length > 0 ? context.parentCandidates[0] : null;
298
+ }
299
+ const transactionPlans = [];
300
+ for (const plan of instructionPlan.plans) {
301
+ const transactionPlan = await traverse2(plan, {
302
+ ...context,
303
+ parent: instructionPlan,
304
+ parentCandidates: candidate ? [candidate] : []
305
+ });
306
+ if (transactionPlan) {
307
+ candidate = getSequentialCandidate(transactionPlan);
308
+ const newPlans = transactionPlan.kind === "sequential" && (transactionPlan.divisible || !instructionPlan.divisible) ? transactionPlan.plans : [transactionPlan];
309
+ transactionPlans.push(...newPlans);
310
+ }
311
+ }
312
+ if (transactionPlans.length === 1) {
313
+ return transactionPlans[0];
314
+ }
315
+ if (transactionPlans.length === 0) {
316
+ return null;
317
+ }
318
+ return {
319
+ divisible: instructionPlan.divisible,
320
+ kind: "sequential",
321
+ plans: transactionPlans
322
+ };
323
+ }
324
+ async function traverseParallel2(instructionPlan, context) {
325
+ const candidates = [...context.parentCandidates];
326
+ const transactionPlans = [];
327
+ const sortedChildren = Array.from(instructionPlan.plans).sort(
328
+ (a, b) => Number(a.kind === "messagePacker") - Number(b.kind === "messagePacker")
329
+ );
330
+ for (const plan of sortedChildren) {
331
+ const transactionPlan = await traverse2(plan, {
332
+ ...context,
333
+ parent: instructionPlan,
334
+ parentCandidates: candidates
335
+ });
336
+ if (transactionPlan) {
337
+ candidates.push(...getParallelCandidates(transactionPlan));
338
+ const newPlans = transactionPlan.kind === "parallel" ? transactionPlan.plans : [transactionPlan];
339
+ transactionPlans.push(...newPlans);
340
+ }
341
+ }
342
+ if (transactionPlans.length === 1) {
343
+ return transactionPlans[0];
344
+ }
345
+ if (transactionPlans.length === 0) {
346
+ return null;
347
+ }
348
+ return { kind: "parallel", plans: transactionPlans };
349
+ }
350
+ async function traverseSingle2(instructionPlan, context) {
351
+ const predicate = (message2) => transactionMessages.appendTransactionMessageInstructions([instructionPlan.instruction], message2);
352
+ const candidate = await selectAndMutateCandidate(context, context.parentCandidates, predicate);
353
+ if (candidate) {
354
+ return null;
355
+ }
356
+ const message = await createNewMessage(context, predicate);
357
+ return { kind: "single", message };
358
+ }
359
+ async function traverseMessagePacker(instructionPlan, context) {
360
+ const messagePacker = instructionPlan.getMessagePacker();
361
+ const transactionPlans = [];
362
+ const candidates = [...context.parentCandidates];
363
+ while (!messagePacker.done()) {
364
+ const candidate = await selectAndMutateCandidate(context, candidates, messagePacker.packMessageToCapacity);
365
+ if (!candidate) {
366
+ const message = await createNewMessage(context, messagePacker.packMessageToCapacity);
367
+ const newPlan = { kind: "single", message };
368
+ transactionPlans.push(newPlan);
369
+ }
370
+ }
371
+ if (transactionPlans.length === 1) {
372
+ return transactionPlans[0];
373
+ }
374
+ if (transactionPlans.length === 0) {
375
+ return null;
376
+ }
377
+ if (context.parent?.kind === "parallel") {
378
+ return { kind: "parallel", plans: transactionPlans };
379
+ }
380
+ return {
381
+ divisible: context.parent?.kind === "sequential" ? context.parent.divisible : true,
382
+ kind: "sequential",
383
+ plans: transactionPlans
384
+ };
385
+ }
386
+ function getSequentialCandidate(latestPlan) {
387
+ if (latestPlan.kind === "single") {
388
+ return latestPlan;
389
+ }
390
+ if (latestPlan.kind === "sequential" && latestPlan.plans.length > 0) {
391
+ return getSequentialCandidate(latestPlan.plans[latestPlan.plans.length - 1]);
392
+ }
393
+ return null;
394
+ }
395
+ function getParallelCandidates(latestPlan) {
396
+ return getAllSingleTransactionPlans(latestPlan);
397
+ }
398
+ async function selectAndMutateCandidate(context, candidates, predicate) {
399
+ for (const candidate of candidates) {
400
+ try {
401
+ const message = await promises.getAbortablePromise(
402
+ Promise.resolve(
403
+ context.onTransactionMessageUpdated(predicate(candidate.message), {
404
+ abortSignal: context.abortSignal
405
+ })
406
+ ),
407
+ context.abortSignal
408
+ );
409
+ if (transactions.getTransactionMessageSize(message) <= transactions.TRANSACTION_SIZE_LIMIT) {
410
+ candidate.message = message;
411
+ return candidate;
412
+ }
413
+ } catch (error) {
414
+ if (errors.isSolanaError(error, errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN)) ; else {
415
+ throw error;
416
+ }
417
+ }
418
+ }
419
+ return null;
420
+ }
421
+ async function createNewMessage(context, predicate) {
422
+ const newMessage = await promises.getAbortablePromise(
423
+ Promise.resolve(context.createTransactionMessage({ abortSignal: context.abortSignal })),
424
+ context.abortSignal
425
+ );
426
+ const updatedMessage = await promises.getAbortablePromise(
427
+ Promise.resolve(
428
+ context.onTransactionMessageUpdated(predicate(newMessage), { abortSignal: context.abortSignal })
429
+ ),
430
+ context.abortSignal
431
+ );
432
+ const updatedMessageSize = transactions.getTransactionMessageSize(updatedMessage);
433
+ if (updatedMessageSize > transactions.TRANSACTION_SIZE_LIMIT) {
434
+ const newMessageSize = transactions.getTransactionMessageSize(newMessage);
435
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN, {
436
+ numBytesRequired: updatedMessageSize - newMessageSize,
437
+ numFreeBytes: transactions.TRANSACTION_SIZE_LIMIT - newMessageSize
438
+ });
439
+ }
440
+ return updatedMessage;
441
+ }
442
+ function freezeTransactionPlan(plan) {
443
+ const kind = plan.kind;
444
+ switch (kind) {
445
+ case "single":
446
+ return singleTransactionPlan(plan.message);
447
+ case "sequential":
448
+ return plan.divisible ? sequentialTransactionPlan(plan.plans.map(freezeTransactionPlan)) : nonDivisibleSequentialTransactionPlan(plan.plans.map(freezeTransactionPlan));
449
+ case "parallel":
450
+ return parallelTransactionPlan(plan.plans.map(freezeTransactionPlan));
451
+ default:
452
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INVARIANT_VIOLATION__INVALID_TRANSACTION_PLAN_KIND, { kind });
453
+ }
454
+ }
455
+ function fitEntirePlanInsideMessage(instructionPlan, message) {
456
+ let newMessage = message;
457
+ const kind = instructionPlan.kind;
458
+ switch (kind) {
459
+ case "sequential":
460
+ case "parallel":
461
+ for (const plan of instructionPlan.plans) {
462
+ newMessage = fitEntirePlanInsideMessage(plan, newMessage);
463
+ }
464
+ return newMessage;
465
+ case "single":
466
+ newMessage = transactionMessages.appendTransactionMessageInstructions([instructionPlan.instruction], message);
467
+ const newMessageSize = transactions.getTransactionMessageSize(newMessage);
468
+ if (newMessageSize > transactions.TRANSACTION_SIZE_LIMIT) {
469
+ const baseMessageSize = transactions.getTransactionMessageSize(message);
470
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INSTRUCTION_PLANS__MESSAGE_CANNOT_ACCOMMODATE_PLAN, {
471
+ numBytesRequired: newMessageSize - baseMessageSize,
472
+ numFreeBytes: transactions.TRANSACTION_SIZE_LIMIT - baseMessageSize
473
+ });
474
+ }
475
+ return newMessage;
476
+ case "messagePacker":
477
+ const messagePacker = instructionPlan.getMessagePacker();
478
+ while (!messagePacker.done()) {
479
+ newMessage = messagePacker.packMessageToCapacity(message);
480
+ }
481
+ return newMessage;
482
+ default:
483
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INVARIANT_VIOLATION__INVALID_INSTRUCTION_PLAN_KIND, { kind });
484
+ }
485
+ }
486
+
487
+ exports.canceledSingleTransactionPlanResult = canceledSingleTransactionPlanResult;
488
+ exports.createTransactionPlanExecutor = createTransactionPlanExecutor;
489
+ exports.createTransactionPlanner = createTransactionPlanner;
490
+ exports.failedSingleTransactionPlanResult = failedSingleTransactionPlanResult;
491
+ exports.getAllSingleTransactionPlans = getAllSingleTransactionPlans;
118
492
  exports.getLinearMessagePackerInstructionPlan = getLinearMessagePackerInstructionPlan;
119
493
  exports.getMessagePackerInstructionPlanFromInstructions = getMessagePackerInstructionPlanFromInstructions;
120
494
  exports.getReallocMessagePackerInstructionPlan = getReallocMessagePackerInstructionPlan;
121
495
  exports.nonDivisibleSequentialInstructionPlan = nonDivisibleSequentialInstructionPlan;
496
+ exports.nonDivisibleSequentialTransactionPlan = nonDivisibleSequentialTransactionPlan;
497
+ exports.nonDivisibleSequentialTransactionPlanResult = nonDivisibleSequentialTransactionPlanResult;
122
498
  exports.parallelInstructionPlan = parallelInstructionPlan;
499
+ exports.parallelTransactionPlan = parallelTransactionPlan;
500
+ exports.parallelTransactionPlanResult = parallelTransactionPlanResult;
123
501
  exports.sequentialInstructionPlan = sequentialInstructionPlan;
502
+ exports.sequentialTransactionPlan = sequentialTransactionPlan;
503
+ exports.sequentialTransactionPlanResult = sequentialTransactionPlanResult;
124
504
  exports.singleInstructionPlan = singleInstructionPlan;
505
+ exports.singleTransactionPlan = singleTransactionPlan;
506
+ exports.successfulSingleTransactionPlanResult = successfulSingleTransactionPlanResult;
125
507
  //# sourceMappingURL=index.browser.cjs.map
126
508
  //# sourceMappingURL=index.browser.cjs.map