Skip to content

Commit

Permalink
Parallelize calls
Browse files Browse the repository at this point in the history
  • Loading branch information
ChewingGlass committed Dec 15, 2023
1 parent 2c6ec96 commit 77ea574
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 10 deletions.
64 changes: 63 additions & 1 deletion packages/spl-utils/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ async function withRetries<A>(
throw new Error("Failed after retries")
}

type Status = {
export type Status = {
totalProgress: number;
currentBatchProgress: number;
currentBatchSize: number;
Expand Down Expand Up @@ -637,3 +637,65 @@ async function getAllTxns(
)
).flat();
}

// Batch instructions parallel into as many txs as it takes
export async function batchParallelInstructions(
provider: AnchorProvider,
instructions: TransactionInstruction[],
onProgress?: (status: Status) => void,
triesRemaining: number = 10 // Number of blockhashes to try resending txs with before giving up
): Promise<void> {
let currentTxInstructions: TransactionInstruction[] = [];
const blockhash = (await provider.connection.getLatestBlockhash()).blockhash;
const transactions: Transaction[] = [];

for (const instruction of instructions) {
currentTxInstructions.push(instruction);
const tx = new Transaction({
feePayer: provider.wallet.publicKey,
recentBlockhash: blockhash,
});
tx.add(...currentTxInstructions);
try {
if (
tx.serialize({
requireAllSignatures: false,
verifySignatures: false,
}).length >=
1232 - (64 + 32) * tx.signatures.length
) {
// yes it's ugly to throw and catch, but .serialize can _also_ throw this error
throw new Error("Transaction too large");
}
} catch (e: any) {
if (e.toString().includes("Transaction too large")) {
currentTxInstructions.pop();
const tx = new Transaction({
feePayer: provider.wallet.publicKey,
recentBlockhash: blockhash,
});
tx.add(...currentTxInstructions);
transactions.push(tx);
currentTxInstructions = [instruction];
} else {
throw e;
}
}
}

if (currentTxInstructions.length > 0) {
const tx = new Transaction({
feePayer: provider.wallet.publicKey,
recentBlockhash: blockhash,
});
tx.add(...currentTxInstructions);
transactions.push(tx);
}

await bulkSendTransactions(
provider,
transactions,
onProgress,
triesRemaining
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
delegatedPositionKey,
init,
} from "@helium/helium-sub-daos-sdk";
import { chunks, sendMultipleInstructions } from "@helium/spl-utils";
import { batchParallelInstructions, chunks, sendMultipleInstructions, Status } from "@helium/spl-utils";
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
import { useAsyncCallback } from "react-async-hook";
import { useHeliumVsrState } from "../contexts/heliumVsrContext";
Expand All @@ -19,9 +19,11 @@ export const useClaimAllPositionsRewards = () => {
async ({
positions,
programId = PROGRAM_ID,
onProgress,
}: {
positions: PositionWithMeta[];
programId?: PublicKey;
onProgress?: (status: Status) => void;
}) => {
const isInvalid =
!unixNow || !provider || !positions.every((pos) => pos.hasRewards);
Expand Down Expand Up @@ -68,6 +70,12 @@ export const useClaimAllPositionsRewards = () => {
);
}

await batchParallelInstructions(
provider,
multiDemArray.flat(),
onProgress
);

for (const positionInsturctions of multiDemArray) {
// This is an arbitrary threshold and we assume that up to 4 instructions can be inserted as a single Tx
const ixsChunks = chunks(positionInsturctions, 4);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
delegatedPositionKey,
init,
} from "@helium/helium-sub-daos-sdk";
import { chunks, sendMultipleInstructions } from "@helium/spl-utils";
import { batchParallelInstructions, Status } from "@helium/spl-utils";
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
import { useAsyncCallback } from "react-async-hook";
import { useHeliumVsrState } from "../contexts/heliumVsrContext";
Expand All @@ -19,9 +19,11 @@ export const useClaimPositionRewards = () => {
async ({
position,
programId = PROGRAM_ID,
onProgress,
}: {
position: PositionWithMeta;
programId?: PublicKey;
onProgress?: (status: Status) => void;
}) => {
const isInvalid = !unixNow || !provider || !position.hasRewards;

Expand Down Expand Up @@ -60,13 +62,7 @@ export const useClaimPositionRewards = () => {
)
);

// This is an arbitrary threshold and we assume that up to 4 instructions can be inserted as a single Tx
const ixsChunks = chunks(instructions, 4);
await sendMultipleInstructions(
provider,
ixsChunks,
ixsChunks.map((_) => [])
);
await batchParallelInstructions(provider, instructions, onProgress);
}
}
);
Expand Down

0 comments on commit 77ea574

Please sign in to comment.