Merge pull request #62 from switchboard-xyz/pack_instructions

Update packInstructions
This commit is contained in:
Jackson Jessup 2022-09-22 15:05:09 -04:00 committed by GitHub
commit c9116c035d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 59 additions and 65 deletions

View File

@ -16,7 +16,6 @@ import {
SYSVAR_INSTRUCTIONS_PUBKEY,
SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
Transaction,
TransactionInstruction,
TransactionSignature,
} from "@solana/web3.js";
import { OracleJob } from "@switchboard-xyz/common";
@ -4175,21 +4174,29 @@ export async function sendAll(
* @returns Transaction[]
*/
export function packInstructions(
instructions: (TransactionInstruction | TransactionInstruction[])[],
feePayer: PublicKey = PublicKey.default,
recentBlockhash: string = PublicKey.default.toBase58()
): Transaction[] {
const packed: Transaction[] = [];
let currentTransaction = new Transaction();
currentTransaction.recentBlockhash = recentBlockhash;
currentTransaction.feePayer = feePayer;
instructions: (
| anchor.web3.TransactionInstruction
| anchor.web3.TransactionInstruction[]
)[],
feePayer = anchor.web3.PublicKey.default,
recentBlockhash = anchor.web3.PublicKey.default.toBase58()
): anchor.web3.Transaction[] {
// Constructs a new Transaction.
const buildNewTransaction = (ixns: anchor.web3.TransactionInstruction[]) => {
const txn = new anchor.web3.Transaction();
txn.recentBlockhash = recentBlockhash;
txn.feePayer = feePayer;
return ixns.length ? txn.add(...ixns) : txn;
};
const encodeLength = (bytes: Array<number>, len: number) => {
const getTxnSize = (transaction: anchor.web3.Transaction) => {
const encodeLength = (len: number) => {
const bytes = new Array<number>();
let remLen = len;
for (;;) {
let elem = remLen & 0x7f;
remLen >>= 7;
if (remLen == 0) {
if (remLen === 0) {
bytes.push(elem);
break;
} else {
@ -4197,60 +4204,47 @@ export function packInstructions(
bytes.push(elem);
}
}
return bytes;
};
for (const ixGroup of instructions) {
const ixs = Array.isArray(ixGroup) ? ixGroup : [ixGroup];
for (const ix of ixs) {
// add the new transaction
currentTransaction.add(ix);
try {
return (
transaction.serializeMessage().length +
transaction.signatures.length * 64 +
encodeLength(transaction.signatures.length).length
);
} catch (err) {
return Number.MAX_SAFE_INTEGER;
}
};
const sigCount: number[] = [];
encodeLength(sigCount, currentTransaction.signatures.length);
const packed: anchor.web3.Transaction[] = [];
let currentTransaction = buildNewTransaction([]);
instructions
.map((ixGroup) => (Array.isArray(ixGroup) ? ixGroup : [ixGroup]))
.forEach((ixs) => {
const newTransaction = buildNewTransaction(ixs);
if (
anchor.web3.PACKET_DATA_SIZE <=
currentTransaction.serializeMessage().length +
currentTransaction.signatures.length * 64 +
sigCount.length
) {
// If the aggregator transaction fits, it will serialize without error. We can then push it ahead no problem
const trimmedInstructions = ixs
.map(() => currentTransaction.instructions.pop())
.reverse();
// Every serialize adds the instruction signatures as dependencies
currentTransaction.signatures = [];
const overflowInstructions = trimmedInstructions;
// add the capped transaction to our transaction - only push it if it works
packed.push(currentTransaction);
currentTransaction = new Transaction();
currentTransaction.recentBlockhash = recentBlockhash;
currentTransaction.feePayer = feePayer;
currentTransaction.instructions = overflowInstructions;
const newsc: number[] = [];
encodeLength(newsc, currentTransaction.signatures.length);
if (
anchor.web3.PACKET_DATA_SIZE <=
currentTransaction.serializeMessage().length +
currentTransaction.signatures.length * 64 +
newsc.length
anchor.web3.PACKET_DATA_SIZE >=
getTxnSize(currentTransaction) + getTxnSize(newTransaction)
) {
// If `newTransaction` can be added to current transaction, do so.
currentTransaction.add(...newTransaction.instructions);
} else if (anchor.web3.PACKET_DATA_SIZE <= getTxnSize(newTransaction)) {
// If `newTransaction` is too large to fit in a transaction, throw an error.
throw new Error(
"Instruction packing error: a grouping of instructions must be able to fit into a single transaction"
);
}
}
}
} else {
// If `newTransaction` cannot be added to `currentTransaction`, push `currentTransaction` and move forward.
packed.push(currentTransaction);
currentTransaction = newTransaction;
}
});
// If the final transaction has at least 1 instruction, add it to the pack.
if (currentTransaction.instructions.length > 0) {
packed.push(currentTransaction);
}
return packed;
}