UNPKG

@j0nnyboi/amman

Version:

A modern mandatory toolbelt to help test solana SDK libraries and apps on a locally running validator.

147 lines 6.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.restartValidator = exports.restartValidatorWithSnapshot = exports.restartValidatorWithAccountOverrides = exports.killValidatorChild = exports.waitForValidator = exports.startSolanaValidator = exports.buildSolanaValidatorArgs = void 0; const child_process_1 = require("child_process"); const assets_1 = require("../assets"); const deactivate_features_1 = require("../utils/deactivate-features"); const fs_1 = require("../utils/fs"); const log_1 = require("../utils/log"); const ensure_validator_up_1 = require("./ensure-validator-up"); const prepare_config_1 = require("./prepare-config"); const process_accounts_1 = require("./process-accounts"); const process_snapshot_1 = require("./process-snapshot"); const { logDebug, logInfo, logTrace } = (0, log_1.scopedLog)('validator'); async function buildSolanaValidatorArgs(config, forceClone) { logTrace('config %O', config); const validatorConfig = config.validator; const { programs, accountsCluster, accounts, ledgerDir, resetLedger, limitLedgerSize, websocketUrl, jsonRpcUrl, commitment, matchFeatures, deactivateFeatures, } = validatorConfig; const { assetsFolder } = config; // ----------------- // Setup Solana Config // ----------------- const { configPath, cleanupConfig } = await (0, prepare_config_1.solanaConfig)({ websocketUrl, jsonRpcUrl, commitment, }); let args = ['--quiet', '-C', configPath, '--ledger', ledgerDir]; if (resetLedger) args.push('-r'); args.push(...['--limit-ledger-size', limitLedgerSize.toString()]); // ----------------- // Deploy Programs // ----------------- if (programs.length > 0) { for (const { programId, deployPath } of programs) { if (!(0, fs_1.canAccessSync)(deployPath)) { throw new Error(`Cannot access program deploy path of ${deployPath}`); } args.push('--bpf-program'); args.push(programId); args.push(deployPath); } } // ----------------- // Deactivate Features // ----------------- (0, deactivate_features_1.maybeDeactivateFeatures)(args, matchFeatures, deactivateFeatures); // ----------------- // Add Cloned Accounts // ----------------- const { accountsArgs, persistedAccountInfos, accountsFolder } = await (0, process_accounts_1.processAccounts)(accounts, accountsCluster, assetsFolder, forceClone); args = [...args, ...accountsArgs]; // ----------------- // Add Snapshot // ----------------- const { snapshotArgs, persistedSnapshotAccountInfos, snapshotAccounts, keypairs, } = await (0, process_snapshot_1.processSnapshot)(config.snapshot); args = [...args, ...snapshotArgs]; return { args, persistedAccountInfos, persistedSnapshotAccountInfos, snapshotAccounts, accountsFolder, keypairs, cleanupConfig, }; } exports.buildSolanaValidatorArgs = buildSolanaValidatorArgs; async function startSolanaValidator(args, detached) { logTrace('start %O', args); const child = (0, child_process_1.spawn)('solana-test-validator', args, { detached, stdio: 'inherit', }); child.unref(); await new Promise((resolve, reject) => { child.on('spawn', resolve).on('error', reject); }); return child; } exports.startSolanaValidator = startSolanaValidator; async function waitForValidator(jsonRpcUrl, verifyFees, cleanupConfig) { await (0, ensure_validator_up_1.ensureValidatorIsUp)(jsonRpcUrl, verifyFees); await cleanupConfig(); logInfo('up and running'); } exports.waitForValidator = waitForValidator; function killValidatorChild(child) { child.kill(); return new Promise((resolve, reject) => { child.on('exit', resolve).on('error', reject); }); } exports.killValidatorChild = killValidatorChild; /** * Attempts to kill and restart the validator creating a snapshot of accounts and keypairs first. * That same snapshot is then loaded on restart. * * @param accountOverrides allow to override some accounts that are written to the snapshot * */ async function restartValidatorWithAccountOverrides(accountStates, ammanState, addresses, // Keyed pubkey:label accountLabels, keypairs, accountOverrides) { const { config: snapshot, cleanupSnapshotDir } = await (0, assets_1.createTemporarySnapshot)(addresses, accountLabels, keypairs, accountOverrides); const config = { ...ammanState.config, snapshot }; const res = await restartValidator(accountStates, ammanState, config); await cleanupSnapshotDir(); return res; } exports.restartValidatorWithAccountOverrides = restartValidatorWithAccountOverrides; /** * Attempts to kill and restart the validator with the given snapshot. */ async function restartValidatorWithSnapshot(accountStates, ammanState, snapshotLabel) { const snapshot = { ...ammanState.config.snapshot, load: snapshotLabel, }; const config = { ...ammanState.config, snapshot }; return restartValidator(accountStates, ammanState, config); } exports.restartValidatorWithSnapshot = restartValidatorWithSnapshot; /** * Attempts to kill and restart the validator with the provided config. * * NOTE: that for now this seems to only work once, i.e. the validator fails to * handle transactions after it is restarted twice (they time out after 30secs) * */ async function restartValidator(accountStates, ammanState, config) { logDebug('Restarting validator'); accountStates.paused = true; try { await killValidatorChild(ammanState.validator); const { args, cleanupConfig, ...rest } = await buildSolanaValidatorArgs(config, false); const validator = await startSolanaValidator(args, ammanState.detached); ammanState.validator = validator; await waitForValidator(config.validator.jsonRpcUrl, config.validator.verifyFees, cleanupConfig); return { args, ...rest }; } finally { accountStates.paused = false; } } exports.restartValidator = restartValidator; //# sourceMappingURL=solana-validator.js.map