123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- /**
- * Generate instructions with repetitive accounts and add them to the bench program.
- */
- import * as fs from "fs/promises";
- import path from "path";
- type Instruction = {
- /** Instruction name */
- name: string;
- /** Each account type in accounts struct */
- accountType: string;
- /** Account macro(`#[account(..)]`) */
- accountMacro?: {
- init: true;
- space?: number | string;
- };
- /** Number of accounts to create per instruction */
- accountCounts?: number[];
- };
- /**
- * The following instructions will be added to the program.
- *
- * If an instruction already exists, it will be skipped.
- */
- const INSTRUCTIONS: Instruction[] = [
- {
- name: "account_info",
- accountType: "AccountInfo<'info>",
- },
- {
- name: "account_empty_init",
- accountType: "Account<'info, Empty>",
- accountMacro: {
- init: true,
- },
- },
- {
- name: "account_empty",
- accountType: "Account<'info, Empty>",
- },
- {
- name: "account_sized_init",
- accountType: "Account<'info, Sized>",
- accountMacro: {
- init: true,
- space: "8 + std::mem::size_of::<Sized>()",
- },
- },
- {
- name: "account_sized",
- accountType: "Account<'info, Sized>",
- },
- {
- name: "account_unsized_init",
- accountType: "Account<'info, Unsized>",
- accountMacro: {
- init: true,
- space: "8 + std::mem::size_of::<Unsized>()",
- },
- },
- {
- name: "account_unsized",
- accountType: "Account<'info, Unsized>",
- },
- {
- name: "boxed_account_empty_init",
- accountType: "Box<Account<'info, Empty>>",
- accountMacro: {
- init: true,
- },
- },
- {
- name: "boxed_account_empty",
- accountType: "Box<Account<'info, Empty>>",
- },
- {
- name: "boxed_account_sized_init",
- accountType: "Box<Account<'info, Sized>>",
- accountMacro: {
- init: true,
- space: "8 + std::mem::size_of::<Sized>()",
- },
- },
- {
- name: "boxed_account_sized",
- accountType: "Box<Account<'info, Sized>>",
- },
- {
- name: "boxed_account_unsized_init",
- accountType: "Box<Account<'info, Unsized>>",
- accountMacro: {
- init: true,
- space: "8 + std::mem::size_of::<Unsized>()",
- },
- },
- {
- name: "boxed_account_unsized",
- accountType: "Box<Account<'info, Unsized>>",
- },
- {
- name: "boxed_interface_account_mint",
- accountType: "Box<InterfaceAccount<'info, Mint>>",
- },
- {
- name: "boxed_interface_account_token",
- accountType: "Box<InterfaceAccount<'info, TokenAccount>>",
- },
- {
- name: "interface_account_mint",
- accountType: "InterfaceAccount<'info, Mint>",
- },
- {
- name: "interface_account_token",
- accountType: "InterfaceAccount<'info, TokenAccount>",
- accountCounts: [1, 2, 4],
- },
- {
- name: "interface",
- accountType: "Interface<'info, TokenInterface>",
- },
- {
- name: "program",
- accountType: "Program<'info, System>",
- },
- {
- name: "signer",
- accountType: "Signer<'info>",
- },
- {
- name: "system_account",
- accountType: "SystemAccount<'info>",
- },
- {
- name: "unchecked_account",
- accountType: "UncheckedAccount<'info>",
- },
- ];
- (async () => {
- // Get the program file
- const programPath = path.join("programs", "bench", "src", "lib.rs");
- let file = await fs.readFile(programPath, {
- encoding: "utf8",
- });
- const create = (
- ix: Omit<Instruction, "accountCounts"> & { count: number }
- ) => {
- // Get the title case of the name for the accounts struct
- const accountsName =
- ix.name[0].toUpperCase() +
- ix.name.slice(1).replace(/_\w/g, (match) => match[1].toUpperCase());
- // Generate accounts
- let accounts = "";
- let accountMacro = "";
- const INDENT = "\n ";
- if (ix.accountMacro?.init) {
- accounts += `${INDENT}#[account(mut)]${INDENT}pub payer: Signer<'info>,`;
- accounts += `${INDENT}pub system_program: Program<'info, System>,`;
- accountMacro += `init, payer = payer, space = ${
- ix.accountMacro.space ?? 8
- }`;
- }
- accountMacro = `${INDENT}#[account(${accountMacro})]`;
- for (let i = 0; i < ix.count; i++) {
- if (ix.accountMacro) {
- accounts += accountMacro;
- }
- accounts += `${INDENT}pub account${i + 1}: ${ix.accountType},`;
- }
- return {
- ix: `
- pub fn ${ix.name}(_ctx: Context<${accountsName}>) -> Result<()> {
- Ok(())
- }`,
- accounts: `
- #[derive(Accounts)]
- pub struct ${accountsName}<'info> {${accounts}\n}`,
- };
- };
- const insert = (index: number, text: string) => {
- file = file.slice(0, index) + "\n" + text + file.slice(index);
- };
- for (const instruction of INSTRUCTIONS) {
- // Default count
- instruction.accountCounts ??= [1, 2, 4, 8];
- for (const count of instruction.accountCounts) {
- // Append count to the end of the instruction name
- const ixName = instruction.name + count;
- // Skip existing instructions
- if (file.includes(`fn ${ixName}`)) {
- continue;
- }
- const { ix, accounts } = create({ ...instruction, name: ixName, count });
- // Get the ix index to start from
- const programIndex = file.indexOf("#[program]");
- const fileStartingFromProgram = file.slice(programIndex);
- // Add instruction
- const ixIndex = programIndex + fileStartingFromProgram.indexOf("\n}");
- insert(ixIndex, ix);
- // Add accounts
- const accountsIndex = file.length - 1;
- insert(accountsIndex, accounts);
- }
- }
- // Save
- await fs.writeFile(programPath, file);
- })();
|