UNPKG

@muirglacier/testcontainers

Version:

A collection of TypeScript + JavaScript tools and libraries for DeFi Blockchain developers to build decentralized finance for Bitcoin

346 lines 14.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MasterNodeRegTestContainer = void 0; const jellyfish_network_1 = require("@muirglacier/jellyfish-network"); const utils_1 = require("../../utils"); const DeFiDContainer_1 = require("../DeFiDContainer"); const index_1 = require("./index"); /** * RegTest with MasterNode preconfigured */ class MasterNodeRegTestContainer extends index_1.RegTestContainer { /** * @param {string} [masternodeKey=RegTestFoundationKeys[0]] pair to use for minting * @param {string} [image=DeFiDContainer.image] docker image name * @param {DockerOptions} [options] */ constructor(masternodeKey = jellyfish_network_1.RegTestFoundationKeys[0], image = DeFiDContainer_1.DeFiDContainer.image, options) { super(image, options); this.masternodeKey = masternodeKey; } /** * Additional debug options turned on for traceability. */ getCmd(opts) { return [ ...super.getCmd(opts), '-dummypos=0', '-spv=1', '-anchorquorum=2', `-masternode_operator=${this.masternodeKey.operator.address}` ]; } /** * @param {number} nblocks to generate * @param {string} address to generate to * @param {number} maxTries */ generate(nblocks, address = this.masternodeKey.operator.address, maxTries = 1000000) { return __awaiter(this, void 0, void 0, function* () { for (let minted = 0, tries = 0; minted < nblocks && tries < maxTries; tries++) { const result = yield this.call('generatetoaddress', [1, address, 1]); if (result === 1) { minted += 1; } } }); } /** * @param {number} nblocks to generate * @param {number} timeout * @param {string} address */ waitForGenerate(nblocks, timeout = 590000, address = this.masternodeKey.operator.address) { return __awaiter(this, void 0, void 0, function* () { const target = (yield this.getBlockCount()) + nblocks; return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const count = yield this.getBlockCount(); if (count > target) { return true; } yield this.generate(1); return false; }), timeout, 100, 'waitForGenerate'); }); } /** * This will automatically import the necessary private key for master to mint tokens */ start(startOptions = {}) { const _super = Object.create(null, { start: { get: () => super.start } }); return __awaiter(this, void 0, void 0, function* () { yield _super.start.call(this, startOptions); yield this.call('importprivkey', [this.masternodeKey.operator.privKey, 'operator', true]); yield this.call('importprivkey', [this.masternodeKey.owner.privKey, 'owner', true]); }); } /** * Wait for block height by minting towards the target * * @param {number} height to wait for * @param {number} [timeout=90000] in ms */ waitForBlockHeight(height, timeout = 590000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const count = yield this.getBlockCount(); if (count > height) { return true; } yield this.generate(1); return false; }), timeout, 100, 'waitForBlockHeight'); }); } /** * Wait for master node wallet coin to be mature for spending. * * A coinbase transaction must be 100 blocks deep before you can spend its outputs. This is a * safeguard to prevent outputs that originate from the coinbase transaction from becoming * un-spendable (in the event the mined block moves out of the active chain due to a fork). * * @param {number} [timeout=180000] in ms */ waitForWalletCoinbaseMaturity(timeout = 180000) { return __awaiter(this, void 0, void 0, function* () { return yield this.waitForBlockHeight(100, timeout); }); } /** * Wait for in wallet balance to be greater than an amount. * This allow test that require fund to wait for fund to be filled up before running the tests. * This method will trigger block generate to get to the required balance faster. * Set `timeout` to higher accordingly when large balance required. * * @param {number} balance to wait for in wallet to be greater than or equal * @param {number} [timeout=300000] in ms * @see waitForWalletCoinbaseMaturity */ waitForWalletBalanceGTE(balance, timeout = 300000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const getbalance = yield this.call('getbalance'); if (getbalance >= balance) { return true; } yield this.generate(1); return false; }), timeout, 100, 'waitForWalletBalanceGTE'); }); } /** * Wait for anchor teams * * @param {number} nodesLength * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ /* istanbul ignore next, TODO(canonbrother) */ waitForAnchorTeams(nodesLength, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const anchorTeams = yield this.call('getanchorteams'); if (anchorTeams.auth.length === nodesLength && anchorTeams.confirm.length === nodesLength) { return true; } return false; }), timeout, 100, 'waitForAnchorTeams'); }); } /** * Wait for anchor auths * * @param {number} nodesLength * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ /* istanbul ignore next, TODO(canonbrother) */ waitForAnchorAuths(nodesLength, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const auths = yield this.call('spv_listanchorauths'); if (auths.length > 0 && auths[0].signers === nodesLength) { return true; } return false; }), timeout, 100, 'waitForAnchorAuths'); }); } /** * Wait for anchor reward confirms * * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ waitForAnchorRewardConfirms(timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { // extra info here // max signers in regtest is 3, others are 5 // majority is defined as 66% above const majority = 2; return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const confirms = yield this.call('spv_listanchorrewardconfirms'); if (confirms.length === 1 && confirms[0].signers >= majority) { return true; } return false; }), timeout, 100, 'waitForAnchorRewardConfrims'); }); } /** * Wait for price become valid * * @param {string} fixedIntervalPriceId * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ waitForPriceValid(fixedIntervalPriceId, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const data = yield this.call('getfixedintervalprice', [fixedIntervalPriceId]); // eslint-disable-next-line if (!data.isLive) { yield this.generate(1); return false; } return true; }), timeout, 100, 'waitForPriceValid'); }); } /** * Wait for price become invalid * * @param {string} fixedIntervalPriceId * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ waitForPriceInvalid(fixedIntervalPriceId, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const data = yield this.call('getfixedintervalprice', [fixedIntervalPriceId]); // eslint-disable-next-line if (data.isLive) { yield this.generate(1); return false; } return true; }), timeout, 100, 'waitForPriceInvalid'); }); } waitForVaultState(vaultId, state, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const vault = yield this.call('getvault', [vaultId]); if (vault.state !== state) { yield this.generate(1); return false; } return true; }), timeout, 100, 'waitForVaultState'); }); } /** * Wait for active price * * @param {string} fixedIntervalPriceId * @param {string} activePrice * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ waitForActivePrice(fixedIntervalPriceId, activePrice, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const data = yield this.call('getfixedintervalprice', [fixedIntervalPriceId]); // eslint-disable-next-line if (data.activePrice.toString() !== activePrice) { yield this.generate(1); return false; } return true; }), timeout, 100, 'waitForActivePrice'); }); } /** * Wait for next price * * @param {string} fixedIntervalPriceId * @param {string} nextPrice * @param {number} [timeout=30000] in ms * @return {Promise<void>} */ waitForNextPrice(fixedIntervalPriceId, nextPrice, timeout = 30000) { return __awaiter(this, void 0, void 0, function* () { return yield utils_1.waitForCondition(() => __awaiter(this, void 0, void 0, function* () { const data = yield this.call('getfixedintervalprice', [fixedIntervalPriceId]); // eslint-disable-next-line if (data.nextPrice.toString() !== nextPrice) { yield this.generate(1); return false; } return true; }), timeout, 100, 'waitForNextPrice'); }); } /** * Fund an address with an amount and wait for 1 confirmation. * Funded address don't have to be tracked within the node wallet. * This allows for light wallet implementation testing. * * @param {string} address to fund * @param {number} amount to fund an address, take note of number precision issues, BigNumber not included in pkg. * @return {Promise<{txid: string, vout: number}>} txid and index of the transaction * @see waitForWalletCoinbaseMaturity * @see waitForWalletBalanceGTE */ fundAddress(address, amount) { return __awaiter(this, void 0, void 0, function* () { const txid = yield this.call('sendtoaddress', [address, amount]); yield this.generate(1); const { vout } = yield this.call('getrawtransaction', [txid, true]); for (const out of vout) { if (out.scriptPubKey.addresses.includes(address)) { return { txid, vout: out.n }; } } throw new Error('getrawtransaction will always return the required vout'); }); } /** * Create a new bech32 address and get the associated priv key for it. * The address is created in the wallet and the priv key is dumped out. * This is to facilitate raw tx feature testing, if you need an address that is not associated with the wallet, * use jellyfish-crypto instead. * * This is not a deterministic feature, each time you run this, you get a different set of address and keys. * * @return {Promise<{ address: string, privKey: string, pubKey: string }>} a new address and it's associated privKey */ newAddressKeys() { return __awaiter(this, void 0, void 0, function* () { const address = yield this.call('getnewaddress', ['', 'bech32']); const privKey = yield this.call('dumpprivkey', [address]); const getaddressinfo = yield this.call('getaddressinfo', [address]); return { address, privKey, pubKey: getaddressinfo.pubkey }; }); } } exports.MasterNodeRegTestContainer = MasterNodeRegTestContainer; //# sourceMappingURL=Masternode.js.map