start-validator.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /* eslint-disable @typescript-eslint/restrict-template-expressions */
  2. /* eslint-disable unicorn/catch-error-name */
  3. /* eslint-disable @typescript-eslint/no-unnecessary-condition */
  4. /* eslint-disable @typescript-eslint/no-base-to-string */
  5. /* eslint-disable no-console */
  6. import { exec } from "node:child_process";
  7. import { mkdtemp } from "node:fs/promises";
  8. import os from "node:os";
  9. import path from "node:path";
  10. import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
  11. import { Connection } from "@solana/web3.js";
  12. import { loadKeypair } from "./keys";
  13. import {
  14. INTEGRITY_POOL_PROGRAM_ADDRESS,
  15. PUBLISHER_CAPS_PROGRAM_ADDRESS,
  16. STAKING_PROGRAM_ADDRESS,
  17. } from "../src/constants";
  18. export function getConnection(): Connection {
  19. return new Connection(
  20. `http://127.0.0.1:8899`,
  21. AnchorProvider.defaultOptions().commitment,
  22. );
  23. }
  24. /**
  25. * If we abort immediately, the web-sockets are still subscribed, and they give a ton of errors.
  26. * Waiting a few seconds is enough to let the sockets close.
  27. */
  28. export class CustomAbortController {
  29. abortController: AbortController;
  30. constructor(abortController: AbortController) {
  31. this.abortController = abortController;
  32. }
  33. abort() {
  34. return new Promise((resolve) => {
  35. setTimeout(() => {
  36. this.abortController.abort();
  37. resolve(undefined);
  38. }, 5000);
  39. });
  40. }
  41. }
  42. /* Starts a validator at port portNumber with the command line arguments specified after a few basic ones
  43. *
  44. * returns a `{ controller, connection }` struct. Users of this method have to terminate the
  45. * validator by calling :
  46. * ```controller.abort()```
  47. */
  48. export async function startValidatorRaw() {
  49. const connection: Connection = getConnection();
  50. const ledgerDir = await mkdtemp(path.join(os.tmpdir(), "ledger-"));
  51. const internalController: AbortController = new AbortController();
  52. const { signal } = internalController;
  53. const user = loadKeypair(
  54. "integration-tests/keypairs/localnet-authority.json",
  55. );
  56. const command = `solana-test-validator \
  57. --ledger ${ledgerDir} \
  58. --reset \
  59. --mint ${user.publicKey.toBase58()} \
  60. --bpf-program ${STAKING_PROGRAM_ADDRESS.toBase58()} integration-tests/programs/staking.so \
  61. --bpf-program ${INTEGRITY_POOL_PROGRAM_ADDRESS.toBase58()} integration-tests/programs/integrity_pool.so \
  62. --bpf-program ${PUBLISHER_CAPS_PROGRAM_ADDRESS.toBase58()} integration-tests/programs/publisher_caps.so \
  63. `;
  64. exec(command, { signal }, (error, stdout, stderr) => {
  65. if (error?.name.includes("AbortError")) {
  66. // Test complete, this is expected.
  67. return;
  68. }
  69. if (error) {
  70. console.error(`exec error: ${error}`);
  71. return;
  72. }
  73. console.log(`stdout: ${stdout}`);
  74. console.error(`stderr: ${stderr}`);
  75. });
  76. const controller = new CustomAbortController(internalController);
  77. let numRetries = 0;
  78. while (true) {
  79. try {
  80. await new Promise((resolve) => setTimeout(resolve, 1000));
  81. await connection.getSlot();
  82. break;
  83. } catch (e) {
  84. // Bound the number of retries so the tests don't hang if there's some problem blocking
  85. // the connection to the validator.
  86. if (numRetries == 30) {
  87. console.log(
  88. `Failed to start validator or connect to running validator. Caught exception: ${e}`,
  89. );
  90. throw e;
  91. }
  92. numRetries += 1;
  93. }
  94. }
  95. return { controller, connection, wallet: new Wallet(user) };
  96. }