Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
target/
tarpaulin-out/
tarpaulin-out-up/
tarpaulin-out-up/

scripts/node_modules/
scripts/.yarn
.yarn/
.pnp.cjs
.pnp.loader.mjs
1 change: 1 addition & 0 deletions scripts/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
31 changes: 31 additions & 0 deletions scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"packageManager": "yarn@4.14.1",
"type": "module",
"scripts": {
"repro": "tsx repro.ts",
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
},
"dependencies": {
"@coral-xyz/anchor": "0.32.1",
"@coral-xyz/spl-token": "0.32.1",
"@solana-developers/helpers": "2.8.0",
"@solana-program/token": "^0.13.0",
"@solana/client": "^1.7.0",
"@solana/kit": "^6.9.0",
"@solana/spl-token": "^0.4.8",
"@solana/web3-compat": "^0.0.21",
"@solana/web3.js": "^1.98.0",
"bignumber.js": "11.1.3",
"litesvm": "1.1.0"
},
"devDependencies": {
"@types/bn.js": "^5.1.0",
"@types/node": "^24.0.0",
"big.js": "^6.2.1",
"prettier": "^2.6.2",
"ts-node": "^10.9.1",
"tsx": "^4.20.0",
"typescript": "^5.7.3"
}
}
144 changes: 144 additions & 0 deletions scripts/repro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import BigNumber from "bignumber.js";
import { createRequire } from "module";
import { readFileSync } from "fs";
import {
MINT_SIZE,
MintLayout,
} from "@solana/spl-token";
import {
appendTransactionMessageInstruction,
createTransactionMessage,
generateKeyPairSigner,
lamports,
setTransactionMessageFeePayerSigner,
signTransactionMessageWithSigners,
type Address,
type KeyPairSigner,
} from "@solana/kit";
import {
findAssociatedTokenPda,
getCreateAssociatedTokenInstruction,
TOKEN_PROGRAM_ADDRESS,
} from "@solana-program/token";
import {
PublicKey,
} from "@solana/web3.js";
import {
FeatureSet,
LiteSVM,
} from "litesvm";

// If "send" or "simulate" this script will hang. Set this to "skip" to avoid sending the tx: this
// script will complete and will not hang.
const MODE = process.env.MODE ?? "send";
const SOME_CONST = 6;
const PAYER_LAMPORTS = 1_000_000_000_000n;
const require = createRequire(import.meta.url);
const ACCOUNT_DATA_DIRECT_MAPPING =
"6f2qai82RU7Dutj1WJfRzLJKYA36QWvTa89CR1imgj7N";

const createMintData = (mintAuthority: PublicKey): Buffer => {
const data = Buffer.alloc(MINT_SIZE);
MintLayout.encode(
{
mintAuthorityOption: 1,
mintAuthority,
supply: 0n,
decimals: SOME_CONST,
isInitialized: true,
freezeAuthorityOption: 0,
freezeAuthority: PublicKey.default,
},
data,
);
return data;
};

const svm = new LiteSVM()
.withLamports(PAYER_LAMPORTS * 2n)
.withTransactionHistory(0n)
.withLogBytesLimit(undefined);

// if (process.env.FEATURE_SOURCE === "repo") {
// const featureSet = new FeatureSet();
// const featuresSource = readFileSync("../crates/litesvm/src/features.rs", "utf8");
// for (const match of featuresSource.matchAll(/address!\("([^"]+)"\)/g)) {
// featureSet.activate(new PublicKey(match[1]).toBytes(), 0n);
// }
// for (const feature of (process.env.EXTRA_FEATURES ?? "").split(",")) {
// if (feature.length > 0) {
// featureSet.activate(new PublicKey(feature).toBytes(), 0n);
// }
// }
// if (process.env.NO_DIRECT_MAPPING === "1") {
// featureSet.deactivate(new PublicKey(ACCOUNT_DATA_DIRECT_MAPPING).toBytes());
// }
// svm.withFeatureSet(featureSet);
// } else if (process.env.ALL_FEATURES === "1" || process.env.NO_DIRECT_MAPPING === "1") {
// const featureSet = FeatureSet.allEnabled();
// if (process.env.NO_DIRECT_MAPPING === "1") {
// featureSet.deactivate(new PublicKey(ACCOUNT_DATA_DIRECT_MAPPING).toBytes());
// }
// svm.withFeatureSet(featureSet);
// }

const payer: KeyPairSigner = await generateKeyPairSigner();
const owner = await generateKeyPairSigner();
const mint = await generateKeyPairSigner();
const [associatedTokenAccount] = await findAssociatedTokenPda({
owner: owner.address,
mint: mint.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});

svm.airdrop(payer.address, lamports(PAYER_LAMPORTS));
svm.setAccount({
address: mint.address,
executable: false,
programAddress: TOKEN_PROGRAM_ADDRESS,
lamports: lamports(9999999n),
data: createMintData(PublicKey.default),
space: 0n,
});

// Note: a simple transfer or various other kinds of ix will not cause the hang: creating an ATA is
// the only example noted so far.
const message = appendTransactionMessageInstruction(
getCreateAssociatedTokenInstruction({
payer,
ata: associatedTokenAccount,
owner: owner.address,
mint: mint.address,
}),
svm.setTransactionMessageLifetimeUsingLatestBlockhash(
setTransactionMessageFeePayerSigner(
payer,
createTransactionMessage({ version: 0 }),
),
),
);
const tx = await signTransactionMessageWithSigners(message);

console.log(`[bnstall] before ATA ${MODE}`);
// Note: Send OR simulate BOTH TRIGGER the bug.
if (MODE === "send") {
svm.sendTransaction(tx);
} else if (MODE === "simulate") {
svm.simulateTransaction(tx);
} else if (MODE !== "skip") {
throw new Error(`Unknown MODE: ${MODE}`);
}
console.log(`[bnstall] after ATA ${MODE}`);

console.log("[bnstall] node", process.version);
console.log("[bnstall] bignumber path", require.resolve("bignumber.js"));
console.log(
"[bnstall] bignumber version",
require("bignumber.js/package.json").version,
);
console.log("[bnstall] BigNumber config", BigNumber.config());

console.log("[bnstall] before math");
// Hangs here (or on any BigNumber div or various other number operations)
const out = new BigNumber("100000000").div("1000000");
console.log("[bnstall] after math", out.toString());
14 changes: 14 additions & 0 deletions scripts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"types": ["node"],
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ES2022",
"esModuleInterop": true,
"strict": false,
"strictNullChecks": false,
"sourceMap": true,
"resolveJsonModule": true
}
}
Loading