main.test.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { Keypair, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
  2. import { assert } from 'chai';
  3. import { describe, it } from 'mocha';
  4. import { BanksClient, ProgramTestContext, start } from 'solana-bankrun';
  5. type GoToTheParkData = {
  6. name: string;
  7. height: bigint;
  8. };
  9. type GoToTheParkDataRaw = {
  10. name: Uint8Array;
  11. height: bigint;
  12. };
  13. const instructionDiscriminators = {
  14. goToThePark: Buffer.from([0]),
  15. };
  16. const encodeString = (str: string, length: number): Uint8Array => {
  17. const buffer = Buffer.alloc(length, 0);
  18. buffer.write(str, 'utf-8');
  19. return Uint8Array.from(buffer);
  20. };
  21. const decodeString = (data: Uint8Array): string => {
  22. return Buffer.from(data).toString('utf-8').replace(/\0/g, '');
  23. };
  24. const encodeBigInt = (value: bigint): Uint8Array => {
  25. const buffer = Buffer.alloc(8);
  26. buffer.writeBigUInt64LE(value, 0);
  27. return Uint8Array.from(buffer);
  28. };
  29. const createGoToTheParkBuffer = (data: GoToTheParkData): Buffer => {
  30. const name = encodeString(data.name, 64);
  31. const height = encodeBigInt(data.height); // 8 bytes
  32. return Buffer.concat([instructionDiscriminators.goToThePark, name, height]);
  33. };
  34. const toGoToTheParkData = (data: GoToTheParkDataRaw): GoToTheParkData => {
  35. return {
  36. name: decodeString(data.name),
  37. height: data.height,
  38. };
  39. };
  40. describe('processing instructions', async () => {
  41. const PROGRAM_ID = new PublicKey('z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35');
  42. let context: ProgramTestContext;
  43. let client: BanksClient;
  44. let payer: Keypair;
  45. before(async () => {
  46. context = await start([{ name: 'processing_instructions_program', programId: PROGRAM_ID }], []);
  47. client = context.banksClient;
  48. payer = context.payer;
  49. });
  50. it('should go to the park!', async () => {
  51. // data for the instruction
  52. const jimmy: GoToTheParkData = {
  53. name: 'Jimmy',
  54. height: BigInt(3),
  55. };
  56. const mary: GoToTheParkData = {
  57. name: 'Mary',
  58. height: BigInt(10),
  59. };
  60. const jimmyBuffer = createGoToTheParkBuffer(jimmy);
  61. const maryBuffer = createGoToTheParkBuffer(mary);
  62. // create the instructions
  63. const ix1 = new TransactionInstruction({
  64. programId: PROGRAM_ID,
  65. keys: [{ pubkey: payer.publicKey, isSigner: true, isWritable: true }],
  66. data: jimmyBuffer,
  67. });
  68. const ix2 = new TransactionInstruction({
  69. programId: PROGRAM_ID,
  70. keys: [{ pubkey: payer.publicKey, isSigner: true, isWritable: true }],
  71. data: maryBuffer,
  72. });
  73. // send the transaction
  74. const tx = new Transaction();
  75. tx.recentBlockhash = context.lastBlockhash;
  76. tx.add(ix1).add(ix2).sign(payer);
  77. // process the transaction
  78. const result = await client.processTransaction(tx);
  79. assert.ok(result);
  80. // check the logs
  81. // we got 2 instructions, we must see 2 consecutive logs
  82. // - Welcome to the park, {name}!
  83. // - You are NOT tall enough... and You are tall enough...
  84. assert(!!result.logMessages.find((msg) => msg.includes(`Welcome to the park, ${jimmy.name}!`)));
  85. assert(!!result.logMessages.find((msg) => msg.includes('You are NOT tall enough')));
  86. assert(!!result.logMessages.find((msg) => msg.includes(`Welcome to the park, ${mary.name}!`)));
  87. assert(!!result.logMessages.find((msg) => msg.includes('You are tall enough')));
  88. });
  89. });