errors.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. const assert = require("assert");
  2. const anchor = require("@project-serum/anchor");
  3. const { Account, Transaction, TransactionInstruction } = anchor.web3;
  4. const { TOKEN_PROGRAM_ID, Token } = require("@solana/spl-token");
  5. // sleep to allow logs to come in
  6. const sleep = (ms) =>
  7. new Promise((resolve) => {
  8. setTimeout(() => resolve(), ms);
  9. });
  10. const withLogTest = async (callback, expectedLogs) => {
  11. let logTestOk = false;
  12. const listener = anchor.getProvider().connection.onLogs(
  13. "all",
  14. (logs) => {
  15. const index = logs.logs.findIndex(
  16. (logLine) => logLine === expectedLogs[0]
  17. );
  18. if (index === -1) {
  19. console.log("Expected: ");
  20. console.log(expectedLogs);
  21. console.log("Actual: ");
  22. console.log(logs);
  23. } else {
  24. const actualLogs = logs.logs.slice(index, index + expectedLogs.length);
  25. for (let i = 0; i < expectedLogs.length; i++) {
  26. if (actualLogs[i] !== expectedLogs[i]) {
  27. console.log("Expected: ");
  28. console.log(expectedLogs);
  29. console.log("Actual: ");
  30. console.log(logs);
  31. return;
  32. }
  33. }
  34. logTestOk = true;
  35. }
  36. },
  37. "recent"
  38. );
  39. try {
  40. await callback();
  41. } catch (err) {
  42. anchor.getProvider().connection.removeOnLogsListener(listener);
  43. throw err;
  44. }
  45. await sleep(3000);
  46. anchor.getProvider().connection.removeOnLogsListener(listener);
  47. assert.ok(logTestOk);
  48. };
  49. describe("errors", () => {
  50. // Configure the client to use the local cluster.
  51. const localProvider = anchor.Provider.local();
  52. localProvider.opts.skipPreflight = true;
  53. anchor.setProvider(localProvider);
  54. const program = anchor.workspace.Errors;
  55. it("Emits a Hello error", async () => {
  56. await withLogTest(async () => {
  57. try {
  58. const tx = await program.rpc.hello();
  59. assert.ok(false);
  60. } catch (err) {
  61. const errMsg =
  62. "This is an error message clients will automatically display";
  63. assert.equal(err.toString(), errMsg);
  64. assert.equal(err.msg, errMsg);
  65. assert.equal(err.code, 6000);
  66. }
  67. }, [
  68. "Program log: AnchorError thrown in programs/errors/src/lib.rs:13. Error Code: Hello. Error Number: 6000. Error Message: This is an error message clients will automatically display.",
  69. ]);
  70. });
  71. it("Emits a Hello error via require!", async () => {
  72. try {
  73. const tx = await program.rpc.testRequire();
  74. assert.ok(false);
  75. } catch (err) {
  76. const errMsg =
  77. "This is an error message clients will automatically display";
  78. assert.equal(err.toString(), errMsg);
  79. assert.equal(err.msg, errMsg);
  80. assert.equal(err.code, 6000);
  81. }
  82. });
  83. it("Emits a Hello error via err!", async () => {
  84. try {
  85. const tx = await program.rpc.testErr();
  86. assert.ok(false);
  87. } catch (err) {
  88. const errMsg =
  89. "This is an error message clients will automatically display";
  90. assert.equal(err.toString(), errMsg);
  91. assert.equal(err.msg, errMsg);
  92. assert.equal(err.code, 6000);
  93. }
  94. });
  95. it("Logs a ProgramError", async () => {
  96. await withLogTest(async () => {
  97. try {
  98. const tx = await program.rpc.testProgramError();
  99. assert.ok(false);
  100. } catch (err) {
  101. // No-op (withLogTest expects the callback to catch the initial tx error)
  102. }
  103. }, [
  104. "Program log: ProgramError occurred. Error Code: InvalidAccountData. Error Number: 17179869184. Error Message: An account's data contents was invalid.",
  105. ]);
  106. });
  107. it("Logs a ProgramError with source", async () => {
  108. await withLogTest(async () => {
  109. try {
  110. const tx = await program.rpc.testProgramErrorWithSource();
  111. assert.ok(false);
  112. } catch (err) {
  113. // No-op (withLogTest expects the callback to catch the initial tx error)
  114. }
  115. }, [
  116. "Program log: ProgramError thrown in programs/errors/src/lib.rs:38. Error Code: InvalidAccountData. Error Number: 17179869184. Error Message: An account's data contents was invalid.",
  117. ]);
  118. });
  119. it("Emits a HelloNoMsg error", async () => {
  120. try {
  121. const tx = await program.rpc.helloNoMsg();
  122. assert.ok(false);
  123. } catch (err) {
  124. const errMsg = "HelloNoMsg";
  125. assert.equal(err.toString(), errMsg);
  126. assert.equal(err.msg, errMsg);
  127. assert.equal(err.code, 6000 + 123);
  128. }
  129. });
  130. it("Emits a HelloNext error", async () => {
  131. try {
  132. const tx = await program.rpc.helloNext();
  133. assert.ok(false);
  134. } catch (err) {
  135. const errMsg = "HelloNext";
  136. assert.equal(err.toString(), errMsg);
  137. assert.equal(err.msg, errMsg);
  138. assert.equal(err.code, 6000 + 124);
  139. }
  140. });
  141. it("Emits a mut error", async () => {
  142. await withLogTest(async () => {
  143. try {
  144. const tx = await program.rpc.mutError({
  145. accounts: {
  146. myAccount: anchor.web3.SYSVAR_RENT_PUBKEY,
  147. },
  148. });
  149. assert.ok(false);
  150. } catch (err) {
  151. const errMsg = "A mut constraint was violated";
  152. assert.equal(err.toString(), errMsg);
  153. assert.equal(err.msg, errMsg);
  154. assert.equal(err.code, 2000);
  155. }
  156. }, [
  157. "Program log: AnchorError caused by account: my_account. Error Code: ConstraintMut. Error Number: 2000. Error Message: A mut constraint was violated.",
  158. ]);
  159. });
  160. it("Emits a has one error", async () => {
  161. try {
  162. const account = new Account();
  163. const tx = await program.rpc.hasOneError({
  164. accounts: {
  165. myAccount: account.publicKey,
  166. owner: anchor.web3.SYSVAR_RENT_PUBKEY,
  167. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  168. },
  169. instructions: [
  170. await program.account.hasOneAccount.createInstruction(account),
  171. ],
  172. signers: [account],
  173. });
  174. assert.ok(false);
  175. } catch (err) {
  176. const errMsg = "A has_one constraint was violated";
  177. assert.equal(err.toString(), errMsg);
  178. assert.equal(err.msg, errMsg);
  179. assert.equal(err.code, 2001);
  180. }
  181. });
  182. // This test uses a raw transaction and provider instead of a program
  183. // instance since the client won't allow one to send a transaction
  184. // with an invalid signer account.
  185. it("Emits a signer error", async () => {
  186. let signature;
  187. const listener = anchor
  188. .getProvider()
  189. .connection.onLogs("all", (logs) => (signature = logs.signature));
  190. try {
  191. const tx = new Transaction();
  192. tx.add(
  193. new TransactionInstruction({
  194. keys: [
  195. {
  196. pubkey: anchor.web3.SYSVAR_RENT_PUBKEY,
  197. isWritable: false,
  198. isSigner: false,
  199. },
  200. ],
  201. programId: program.programId,
  202. data: program.coder.instruction.encode("signer_error", {}),
  203. })
  204. );
  205. await program.provider.send(tx);
  206. assert.ok(false);
  207. } catch (err) {
  208. await sleep(3000);
  209. anchor.getProvider().connection.removeOnLogsListener(listener);
  210. const errMsg = `Error: Raw transaction ${signature} failed ({"err":{"InstructionError":[0,{"Custom":3010}]}})`;
  211. assert.equal(err.toString(), errMsg);
  212. } finally {
  213. anchor.getProvider().connection.removeOnLogsListener(listener);
  214. }
  215. });
  216. it("Emits a raw custom error", async () => {
  217. try {
  218. const tx = await program.rpc.rawCustomError({
  219. accounts: {
  220. myAccount: anchor.web3.SYSVAR_RENT_PUBKEY,
  221. },
  222. });
  223. assert.ok(false);
  224. } catch (err) {
  225. const errMsg = "HelloCustom";
  226. assert.equal(err.toString(), errMsg);
  227. assert.equal(err.msg, errMsg);
  228. assert.equal(err.code, 6000 + 125);
  229. }
  230. });
  231. it("Emits a account not initialized error", async () => {
  232. await withLogTest(async () => {
  233. try {
  234. const tx = await program.rpc.accountNotInitializedError({
  235. accounts: {
  236. notInitializedAccount: new anchor.web3.Keypair().publicKey,
  237. },
  238. });
  239. assert.fail(
  240. "Unexpected success in creating a transaction that should have fail with `AccountNotInitialized` error"
  241. );
  242. } catch (err) {
  243. const errMsg =
  244. "The program expected this account to be already initialized";
  245. assert.equal(err.toString(), errMsg);
  246. }
  247. }, [
  248. "Program log: AnchorError caused by account: not_initialized_account. Error Code: AccountNotInitialized. Error Number: 3012. Error Message: The program expected this account to be already initialized.",
  249. ]);
  250. });
  251. it("Emits an AccountOwnedByWrongProgram error", async () => {
  252. let client = await Token.createMint(
  253. program.provider.connection,
  254. program.provider.wallet.payer,
  255. program.provider.wallet.publicKey,
  256. program.provider.wallet.publicKey,
  257. 9,
  258. TOKEN_PROGRAM_ID
  259. );
  260. await withLogTest(async () => {
  261. try {
  262. const tx = await program.rpc.accountOwnedByWrongProgramError({
  263. accounts: {
  264. wrongAccount: client.publicKey,
  265. },
  266. });
  267. assert.fail(
  268. "Unexpected success in creating a transaction that should have failed with `AccountOwnedByWrongProgram` error"
  269. );
  270. } catch (err) {
  271. const errMsg =
  272. "The given account is owned by a different program than expected";
  273. assert.equal(err.toString(), errMsg);
  274. }
  275. }, [
  276. "Program log: AnchorError caused by account: wrong_account. Error Code: AccountOwnedByWrongProgram. Error Number: 3007. Error Message: The given account is owned by a different program than expected.",
  277. "Program log: Left:",
  278. "Program log: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
  279. "Program log: Right:",
  280. "Program log: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
  281. ]);
  282. });
  283. it("Emits a ValueMismatch error via require_eq", async () => {
  284. await withLogTest(async () => {
  285. try {
  286. const tx = await program.rpc.requireEq();
  287. assert.fail(
  288. "Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
  289. );
  290. } catch (err) {
  291. assert.equal(err.code, 6126);
  292. }
  293. }, [
  294. "Program log: AnchorError thrown in programs/errors/src/lib.rs:68. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch.",
  295. "Program log: Left: 5241",
  296. "Program log: Right: 124124124",
  297. ]);
  298. });
  299. it("Emits a RequireEqViolated error via require_eq", async () => {
  300. await withLogTest(async () => {
  301. try {
  302. const tx = await program.rpc.requireEqDefaultError();
  303. assert.fail(
  304. "Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
  305. );
  306. } catch (err) {
  307. assert.equal(err.code, 2501);
  308. }
  309. }, [
  310. "Program log: AnchorError thrown in programs/errors/src/lib.rs:73. Error Code: RequireEqViolated. Error Number: 2501. Error Message: A require_eq expression was violated.",
  311. "Program log: Left: 5241",
  312. "Program log: Right: 124124124",
  313. ]);
  314. });
  315. it("Emits a ValueMatch error via require_neq", async () => {
  316. await withLogTest(async () => {
  317. try {
  318. const tx = await program.rpc.requireNeq();
  319. assert.fail(
  320. "Unexpected success in creating a transaction that should have failed with `ValueMatch` error"
  321. );
  322. } catch (err) {
  323. assert.equal(err.code, 6127);
  324. }
  325. }, [
  326. "Program log: AnchorError thrown in programs/errors/src/lib.rs:78. Error Code: ValueMatch. Error Number: 6127. Error Message: ValueMatch.",
  327. "Program log: Left: 500",
  328. "Program log: Right: 500",
  329. ]);
  330. });
  331. it("Emits a RequireNeqViolated error via require_neq", async () => {
  332. await withLogTest(async () => {
  333. try {
  334. const tx = await program.rpc.requireNeqDefaultError();
  335. assert.fail(
  336. "Unexpected success in creating a transaction that should have failed with `RequireNeqViolated` error"
  337. );
  338. } catch (err) {
  339. assert.equal(err.code, 2503);
  340. }
  341. }, [
  342. "Program log: AnchorError thrown in programs/errors/src/lib.rs:83. Error Code: RequireNeqViolated. Error Number: 2503. Error Message: A require_neq expression was violated.",
  343. "Program log: Left: 500",
  344. "Program log: Right: 500",
  345. ]);
  346. });
  347. it("Emits a ValueMismatch error via require_keys_eq", async () => {
  348. const someAccount = anchor.web3.Keypair.generate().publicKey;
  349. await withLogTest(async () => {
  350. try {
  351. const tx = await program.rpc.requireKeysEq({
  352. accounts: {
  353. someAccount,
  354. },
  355. });
  356. assert.fail(
  357. "Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
  358. );
  359. } catch (err) {
  360. assert.equal(err.code, 6126);
  361. }
  362. }, [
  363. "Program log: AnchorError thrown in programs/errors/src/lib.rs:88. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch.",
  364. "Program log: Left:",
  365. `Program log: ${someAccount}`,
  366. "Program log: Right:",
  367. `Program log: ${program.programId}`,
  368. ]);
  369. });
  370. it("Emits a RequireKeysEqViolated error via require_keys_eq", async () => {
  371. const someAccount = anchor.web3.Keypair.generate().publicKey;
  372. await withLogTest(async () => {
  373. try {
  374. const tx = await program.rpc.requireKeysEqDefaultError({
  375. accounts: {
  376. someAccount,
  377. },
  378. });
  379. assert.fail(
  380. "Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
  381. );
  382. } catch (err) {
  383. assert.equal(err.code, 2502);
  384. }
  385. }, [
  386. "Program log: AnchorError thrown in programs/errors/src/lib.rs:97. Error Code: RequireKeysEqViolated. Error Number: 2502. Error Message: A require_keys_eq expression was violated.",
  387. "Program log: Left:",
  388. `Program log: ${someAccount}`,
  389. "Program log: Right:",
  390. `Program log: ${program.programId}`,
  391. ]);
  392. });
  393. it("Emits a ValueMatch error via require_keys_neq", async () => {
  394. const someAccount = program.programId;
  395. await withLogTest(async () => {
  396. try {
  397. const tx = await program.rpc.requireKeysNeq({
  398. accounts: {
  399. someAccount,
  400. },
  401. });
  402. assert.fail(
  403. "Unexpected success in creating a transaction that should have failed with `ValueMatch` error"
  404. );
  405. } catch (err) {
  406. assert.equal(err.code, 6127);
  407. }
  408. }, [
  409. "Program log: AnchorError thrown in programs/errors/src/lib.rs:102. Error Code: ValueMatch. Error Number: 6127. Error Message: ValueMatch.",
  410. "Program log: Left:",
  411. `Program log: ${someAccount}`,
  412. "Program log: Right:",
  413. `Program log: ${program.programId}`,
  414. ]);
  415. });
  416. it("Emits a RequireKeysNeqViolated error via require_keys_neq", async () => {
  417. const someAccount = program.programId;
  418. await withLogTest(async () => {
  419. try {
  420. const tx = await program.rpc.requireKeysNeqDefaultError({
  421. accounts: {
  422. someAccount,
  423. },
  424. });
  425. assert.fail(
  426. "Unexpected success in creating a transaction that should have failed with `RequireKeysNeqViolated` error"
  427. );
  428. } catch (err) {
  429. assert.equal(err.code, 2504);
  430. }
  431. }, [
  432. "Program log: AnchorError thrown in programs/errors/src/lib.rs:111. Error Code: RequireKeysNeqViolated. Error Number: 2504. Error Message: A require_keys_neq expression was violated.",
  433. "Program log: Left:",
  434. `Program log: ${someAccount}`,
  435. "Program log: Right:",
  436. `Program log: ${program.programId}`,
  437. ]);
  438. });
  439. it("Emits a ValueLessOrEqual error via require_gt", async () => {
  440. await withLogTest(async () => {
  441. try {
  442. const tx = await program.rpc.requireGt();
  443. assert.fail(
  444. "Unexpected success in creating a transaction that should have failed with `ValueLessOrEqual` error"
  445. );
  446. } catch (err) {
  447. assert.equal(err.code, 6129);
  448. }
  449. }, [
  450. "Program log: AnchorError thrown in programs/errors/src/lib.rs:116. Error Code: ValueLessOrEqual. Error Number: 6129. Error Message: ValueLessOrEqual.",
  451. "Program log: Left: 5",
  452. "Program log: Right: 10",
  453. ]);
  454. });
  455. it("Emits a RequireGtViolated error via require_gt", async () => {
  456. await withLogTest(async () => {
  457. try {
  458. const tx = await program.rpc.requireGtDefaultError();
  459. assert.fail(
  460. "Unexpected success in creating a transaction that should have failed with `RequireGtViolated` error"
  461. );
  462. } catch (err) {
  463. assert.equal(err.code, 2505);
  464. }
  465. }, [
  466. "Program log: AnchorError thrown in programs/errors/src/lib.rs:121. Error Code: RequireGtViolated. Error Number: 2505. Error Message: A require_gt expression was violated.",
  467. "Program log: Left: 10",
  468. "Program log: Right: 10",
  469. ]);
  470. });
  471. it("Emits a ValueLess error via require_gte", async () => {
  472. await withLogTest(async () => {
  473. try {
  474. const tx = await program.rpc.requireGte();
  475. assert.fail(
  476. "Unexpected success in creating a transaction that should have failed with `ValueLess` error"
  477. );
  478. } catch (err) {
  479. assert.equal(err.code, 6128);
  480. }
  481. }, [
  482. "Program log: AnchorError thrown in programs/errors/src/lib.rs:126. Error Code: ValueLess. Error Number: 6128. Error Message: ValueLess.",
  483. "Program log: Left: 5",
  484. "Program log: Right: 10",
  485. ]);
  486. });
  487. it("Emits a RequireGteViolated error via require_gte", async () => {
  488. await withLogTest(async () => {
  489. try {
  490. const tx = await program.rpc.requireGteDefaultError();
  491. assert.fail(
  492. "Unexpected success in creating a transaction that should have failed with `RequireGteViolated` error"
  493. );
  494. } catch (err) {
  495. assert.equal(err.code, 2506);
  496. }
  497. }, [
  498. "Program log: AnchorError thrown in programs/errors/src/lib.rs:131. Error Code: RequireGteViolated. Error Number: 2506. Error Message: A require_gte expression was violated.",
  499. "Program log: Left: 5",
  500. "Program log: Right: 10",
  501. ]);
  502. });
  503. });