UNPKG

@j0nnyboi/amman

Version:

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

231 lines 8.63 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.printableAccount = exports.AccountStates = void 0; const amman_client_1 = require("@j0nnyboi/amman-client"); const web3_js_1 = require("@safecoin/web3.js"); const assert_1 = require("assert"); const bn_js_1 = __importDefault(require("bn.js")); const deep_diff_1 = require("deep-diff"); const Diff = __importStar(require("diff")); const events_1 = __importDefault(require("events")); const log_1 = require("../utils/log"); class AccountStateTracker { constructor() { this.states = []; } add(state) { const lastState = this.states.length > 0 ? this.states[this.states.length - 1] : null; const accountDiff = lastState == null || lastState.account == null || state.account == null ? undefined : (0, deep_diff_1.diff)(lastState.account.pretty(), state.account.pretty()); const processedState = { ...state, accountDiff, timestamp: Date.now().valueOf(), }; const renderedDiff = this.renderDiff(lastState, state); if (renderedDiff != null) { processedState.renderedDiff = renderedDiff; } this.states.push(processedState); } get relayStates() { return this.states .filter((state) => state.account != null) .map(({ account, data, ...rest }) => ({ account: account.pretty(), ...rest, })); } renderDiff(lastState, state) { if ((lastState === null || lastState === void 0 ? void 0 : lastState.rendered) == null) return undefined; if (state.rendered == null) return undefined; return Diff.diffChars(lastState.rendered, state.rendered); } accountStateForSlot(slot) { return this.states.find((state) => state.slot === slot); } accountDataForSlot(slot) { var _a; return (_a = this.accountStateForSlot(slot)) === null || _a === void 0 ? void 0 : _a.data; } } class AccountStates extends events_1.default { constructor(connection, accountProvider, loadedAccountInfos, // label:Keypair loadedKeypairs) { super(); this.connection = connection; this.accountProvider = accountProvider; this.loadedAccountInfos = loadedAccountInfos; this.loadedKeypairs = loadedKeypairs; this.states = new Map(); this.keypairs = new Map(); this._paused = false; this._onLog = async (logs, ctx) => { if (this._paused) return; const tx = await this.connection.getTransaction(logs.signature, { commitment: 'confirmed', }); if (tx == null) { (0, log_1.logDebug)(`Could not find transaction ${logs.signature}`); return; } const nonProgramAddresses = tx.transaction.message .nonProgramIds() .map((x) => x.toBase58()); for (const key of nonProgramAddresses) { if (this._paused) return; this.update(key, ctx.slot); } }; this.connection.onLogs('all', this._onLog, 'confirmed'); for (const [address, info] of this.loadedAccountInfos) { this.update(address, 0, info); } for (const [label, keypair] of this.loadedKeypairs) { this.keypairs.set(keypair.publicKey.toBase58(), { keypair, id: label }); } } get paused() { return this._paused; } set paused(val) { this._paused = val; } // ----------------- // Account States // ----------------- async update(address, slot, accountInfo) { var _a; if (!this.states.has(address)) { this.states.set(address, new AccountStateTracker()); } const res = await this.accountProvider.tryResolveAccount(new web3_js_1.PublicKey(address), accountInfo); if (res == null) return; this.add(address, { ...res, slot }); const states = (_a = this.get(address)) === null || _a === void 0 ? void 0 : _a.relayStates; this.emit(`account-changed:${address}`, states); } add(address, state) { const states = this.get(address); (0, assert_1.strict)(states != null, 'expected states to be set before adding'); states.add(state); } get(address) { return this.states.get(address); } accountStateForSlot(address, slot) { var _a; return (_a = this.get(address)) === null || _a === void 0 ? void 0 : _a.accountStateForSlot(slot); } accountDataForSlot(address, slot) { var _a; return (_a = this.get(address)) === null || _a === void 0 ? void 0 : _a.accountDataForSlot(slot); } allAccountAddresses() { return Array.from(this.states.keys()); } // ----------------- // Keypairs // ----------------- storeKeypair(id, keypair) { this.keypairs.set(keypair.publicKey.toBase58(), { keypair, id }); } labelKeypairs( // Keyed pubkey:label labels) { for (const [key, label] of Object.entries(labels)) { const entry = this.keypairs.get(key); if (entry == null) continue; this.keypairs.set(key, { keypair: entry.keypair, id: label }); } } get allKeypairs() { return this.keypairs; } getKeypairById(keypairId) { for (const { keypair, id } of this.keypairs.values()) { if (id === keypairId) return keypair; } } getKeypairByAddress(address) { var _a; return (_a = this.keypairs.get(address)) === null || _a === void 0 ? void 0 : _a.keypair; } static get instance() { (0, assert_1.strict)(AccountStates._instance != null, 'expected AccountStates instance'); return AccountStates._instance; } static createInstance(connection, accountProvider, loadedAccountInfos, loadedKeypairs) { AccountStates._instance = new AccountStates(connection, accountProvider, loadedAccountInfos, loadedKeypairs); return AccountStates._instance; } } exports.AccountStates = AccountStates; AccountStates._instance = null; function printableAccount(account) { const prettified = {}; for (const [key, val] of Object.entries(account)) { if (val == null) continue; if (typeof val.pretty === 'function') { prettified[key] = val.pretty(); } if (bn_js_1.default.isBN(val) || (typeof val === 'object' && 'negative' in val && 'words' in val && 'red' in val)) { prettified[key] = new bn_js_1.default(val).toNumber(); } else if ((0, amman_client_1.isKeyLike)(val)) { prettified[key] = (0, amman_client_1.publicKeyString)(val); } else if (Array.isArray(val)) { prettified[key] = val.map((val) => JSON.stringify(printableAccount(val))); } else if (typeof val === 'object') { prettified[key] = JSON.stringify(printableAccount(val), null, 2); } else { prettified[key] = val; } } return prettified; } exports.printableAccount = printableAccount; //# sourceMappingURL=state.js.map