Skip to content

Commit 3c9484f

Browse files
authored
Remove getAll function from IterableInstructionPlan (#17)
1 parent b9daf78 commit 3c9484f

3 files changed

Lines changed: 137 additions & 35 deletions

File tree

clients/js/src/instructionPlans/instructionPlan.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ export type IterableInstructionPlan<
3636
TInstruction extends IInstruction = IInstruction,
3737
> = Readonly<{
3838
kind: 'iterable';
39-
/** Get all the instructions in one go or return `null` if not possible */
40-
getAll: () => TInstruction[] | null;
4139
/** Get an iterator for the instructions. */
4240
getIterator: () => InstructionIterator<TInstruction>;
4341
}>;
@@ -102,7 +100,6 @@ export function getLinearIterableInstructionPlan({
102100
}): IterableInstructionPlan {
103101
return {
104102
kind: 'iterable',
105-
getAll: () => [getInstruction(0, totalBytes)],
106103
getIterator: () => {
107104
let offset = 0;
108105
return {
@@ -135,7 +132,6 @@ export function getIterableInstructionPlanFromInstructions<
135132
>(instructions: TInstruction[]): IterableInstructionPlan<TInstruction> {
136133
return {
137134
kind: 'iterable',
138-
getAll: () => instructions,
139135
getIterator: () => {
140136
let instructionIndex = 0;
141137
return {

clients/js/src/instructionPlans/transactionPlannerBase.ts

Lines changed: 137 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -153,16 +153,26 @@ async function traverseSequential(
153153
context.parent &&
154154
(context.parent.kind === 'parallel' || !instructionPlan.divisible);
155155
if (mustEntirelyFitInCandidate) {
156-
const allInstructions = getAllInstructions(instructionPlan);
157-
candidate = allInstructions
158-
? selectCandidate(context.parentCandidates, allInstructions)
159-
: null;
160-
if (candidate && allInstructions) {
161-
await context.addInstructionsToSingleTransactionPlan(
162-
candidate,
163-
allInstructions
156+
for (const parentCandidate of context.parentCandidates) {
157+
const transactionPlan = await traverseWithSingleCandidate(
158+
instructionPlan,
159+
{
160+
...context,
161+
candidate: {
162+
kind: 'single',
163+
message: {
164+
...parentCandidate.message,
165+
instructions: [...parentCandidate.message.instructions],
166+
} as CompilableTransactionMessage,
167+
},
168+
}
164169
);
165-
return null;
170+
if (transactionPlan) {
171+
(parentCandidate as Mutable<SingleTransactionPlan>).message =
172+
transactionPlan.message;
173+
// TODO: Use hook.
174+
return null;
175+
}
166176
}
167177
} else {
168178
candidate =
@@ -327,27 +337,6 @@ function getParallelCandidates(
327337
return getAllSingleTransactionPlans(latestPlan);
328338
}
329339

330-
function getAllInstructions(
331-
instructionPlan: InstructionPlan
332-
): IInstruction[] | null {
333-
if (instructionPlan.kind === 'single') {
334-
return [instructionPlan.instruction];
335-
}
336-
if (instructionPlan.kind === 'iterable') {
337-
return instructionPlan.getAll();
338-
}
339-
return instructionPlan.plans.reduce(
340-
(acc, plan) => {
341-
if (acc === null) return null;
342-
const instructions = getAllInstructions(plan);
343-
if (instructions === null) return null;
344-
acc.push(...instructions);
345-
return acc;
346-
},
347-
[] as IInstruction[] | null
348-
);
349-
}
350-
351340
function selectCandidateForIterator(
352341
candidates: SingleTransactionPlan[],
353342
iterator: InstructionIterator
@@ -395,3 +384,121 @@ function isValidTransactionPlan(transactionPlan: TransactionPlan): boolean {
395384
}
396385
return transactionPlan.plans.every(isValidTransactionPlan);
397386
}
387+
388+
type TraverseWithSingleCandidateContext = {
389+
abortSignal?: AbortSignal;
390+
candidate: SingleTransactionPlan | null;
391+
createSingleTransactionPlan: (
392+
instructions?: IInstruction[],
393+
abortSignal?: AbortSignal
394+
) => Promise<SingleTransactionPlan>;
395+
addInstructionsToSingleTransactionPlan: (
396+
plan: SingleTransactionPlan,
397+
instructions: IInstruction[],
398+
abortSignal?: AbortSignal
399+
) => Promise<void>;
400+
};
401+
402+
async function traverseWithSingleCandidate(
403+
instructionPlan: InstructionPlan,
404+
context: TraverseWithSingleCandidateContext
405+
): Promise<SingleTransactionPlan | null> {
406+
context.abortSignal?.throwIfAborted();
407+
switch (instructionPlan.kind) {
408+
case 'sequential':
409+
return await traverseSequentialWithSingleCandidate(
410+
instructionPlan,
411+
context
412+
);
413+
case 'parallel':
414+
return await traverseParallelWithSingleCandidate(
415+
instructionPlan,
416+
context
417+
);
418+
case 'single':
419+
return await traverseSingleWithSingleCandidate(instructionPlan, context);
420+
case 'iterable':
421+
return await traverseIterableWithSingleCandidate(
422+
instructionPlan,
423+
context
424+
);
425+
default:
426+
instructionPlan satisfies never;
427+
throw new Error(
428+
`Unknown instruction plan kind: ${(instructionPlan as { kind: string }).kind}`
429+
);
430+
}
431+
}
432+
433+
async function traverseSequentialWithSingleCandidate(
434+
instructionPlan: SequentialInstructionPlan,
435+
context: TraverseWithSingleCandidateContext
436+
): Promise<SingleTransactionPlan | null> {
437+
if (context.candidate === null) {
438+
return null;
439+
}
440+
for (const plan of instructionPlan.plans) {
441+
const candidate = await traverseWithSingleCandidate(plan, {
442+
...context,
443+
candidate: context.candidate,
444+
});
445+
if (candidate === null) {
446+
return null;
447+
}
448+
}
449+
return context.candidate;
450+
}
451+
452+
async function traverseParallelWithSingleCandidate(
453+
instructionPlan: ParallelInstructionPlan,
454+
context: TraverseWithSingleCandidateContext
455+
): Promise<SingleTransactionPlan | null> {
456+
if (context.candidate === null) {
457+
return null;
458+
}
459+
for (const plan of instructionPlan.plans) {
460+
const candidate = await traverseWithSingleCandidate(plan, {
461+
...context,
462+
candidate: context.candidate,
463+
});
464+
if (candidate === null) {
465+
return null;
466+
}
467+
}
468+
return context.candidate;
469+
}
470+
471+
async function traverseSingleWithSingleCandidate(
472+
instructionPlan: SingleInstructionPlan,
473+
context: TraverseWithSingleCandidateContext
474+
): Promise<SingleTransactionPlan | null> {
475+
if (context.candidate === null) {
476+
return null;
477+
}
478+
const ix = instructionPlan.instruction;
479+
if (!isValidCandidate(context.candidate, [ix])) {
480+
return null;
481+
}
482+
await context.addInstructionsToSingleTransactionPlan(context.candidate, [ix]);
483+
return context.candidate;
484+
}
485+
486+
async function traverseIterableWithSingleCandidate(
487+
instructionPlan: IterableInstructionPlan,
488+
context: TraverseWithSingleCandidateContext
489+
): Promise<SingleTransactionPlan | null> {
490+
if (context.candidate === null) {
491+
return null;
492+
}
493+
const iterator = instructionPlan.getIterator();
494+
while (iterator.hasNext()) {
495+
const ix = iterator.next(context.candidate.message);
496+
if (!ix || !isValidCandidate(context.candidate, [ix])) {
497+
return null;
498+
}
499+
await context.addInstructionsToSingleTransactionPlan(context.candidate, [
500+
ix,
501+
]);
502+
}
503+
return context.candidate;
504+
}

clients/js/test/instructionPlans/_instructionPlanHelpers.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ export function instructionIteratorFactory() {
3333
return {
3434
get: getInstruction,
3535
kind: 'iterable',
36-
getAll: () => [getInstruction(totalBytes, 0)],
3736
getIterator: () => {
3837
let offset = 0;
3938
return {

0 commit comments

Comments
 (0)