diff --git a/packages/scripts/integration-testing/cosmos.ts b/packages/scripts/integration-testing/cosmos.ts index 5c7b64b3f8..435e470804 100644 --- a/packages/scripts/integration-testing/cosmos.ts +++ b/packages/scripts/integration-testing/cosmos.ts @@ -3,12 +3,12 @@ import fs from "fs/promises"; import { Listr } from "listr2"; import { tmpdir } from "os"; import path from "path"; -import util from "util"; import { cloneRepo } from "./git"; import { zodTryParseJSON } from "../../utils/sanitize"; import { execPromise, + killProcess, mustGetAttr, replaceInFile, sleep, @@ -22,12 +22,17 @@ export const startCosmosLocalnet = async ( home?: string; }, ) => { + let height = opts?.height; + if (!height) { + height = BigInt(0); + } + console.log("🧱 Starting localnet at height " + height); let home = opts?.home; if (!home) { home = await fs.mkdtemp(path.join(tmpdir(), "cosmos-home-")); // run teritorid init --chain-id=testing testing --home=$HOME/.teritorid const initCmd = `${binaryPath} init testing --chain-id testing --home ${home}`; - console.log("> " + initCmd); + console.log("⚙️ " + initCmd); await execPromise(initCmd); await replaceInFile( @@ -38,51 +43,49 @@ export const startCosmosLocalnet = async ( // run teritorid keys add validator --keyring-backend=test --home=$HOME/.teritorid const addValidatorCmd = `${binaryPath} keys add validator --keyring-backend=test --home ${home}`; - console.log("> " + addValidatorCmd); + console.log("⚙️ " + addValidatorCmd); await execPromise(addValidatorCmd); // run teritorid add-genesis-account $(teritorid keys show validator -a --keyring-backend=test --home=$HOME/.teritorid) 100000000000utori,100000000000stake --home=$HOME/.teritorid const addGenesisAccountCmd = `${binaryPath} add-genesis-account $(${binaryPath} keys show validator -a --keyring-backend=test --home ${home}) 100000000000000000utori,100000000000000000stake --home ${home}`; - console.log("> " + addGenesisAccountCmd); + console.log("⚙️ " + addGenesisAccountCmd); await execPromise(addGenesisAccountCmd); // run teritorid keys add testnet-adm --keyring-backend=test --home=$HOME/.teritorid const addTestnetAdmCmd = `${binaryPath} keys add testnet-adm --keyring-backend=test --home ${home}`; - console.log("> " + addTestnetAdmCmd); + console.log("⚙️ " + addTestnetAdmCmd); await execPromise(addTestnetAdmCmd); // run teritorid add-genesis-account $(teritorid keys show validator -a --keyring-backend=test --home=$HOME/.teritorid) 100000000000utori,100000000000stake --home=$HOME/.teritorid const addTestnetAdmGenesisAccountCmd = `${binaryPath} add-genesis-account $(${binaryPath} keys show testnet-adm -a --keyring-backend=test --home ${home}) 100000000000000000utori,100000000000000000stake --home ${home}`; - console.log("> " + addTestnetAdmGenesisAccountCmd); + console.log("⚙️ " + addTestnetAdmGenesisAccountCmd); await execPromise(addTestnetAdmGenesisAccountCmd); // run teritorid gentx validator 500000000stake --keyring-backend=test --home=$HOME/.teritorid --chain-id=testing const gentxCmd = `${binaryPath} gentx validator 500000000stake --keyring-backend=test --home ${home} --chain-id=testing`; - console.log("> " + gentxCmd); + console.log("⚙️ " + gentxCmd); await execPromise(gentxCmd); // run teritorid collect-gentxs --home=$HOME/.teritorid const collectGentxsCmd = `${binaryPath} collect-gentxs --home ${home}`; - console.log("> " + collectGentxsCmd); + console.log("⚙️ " + collectGentxsCmd); await execPromise(collectGentxsCmd); } const cmd = `${binaryPath} start --home ${home}`; - console.log("> " + cmd); + console.log("⚙️ " + cmd); - const result = util.promisify(child_process.exec)(cmd, { + const result = execPromise(cmd, { encoding: "utf-8", }); - let height = opts?.height; - if (!height) { - height = BigInt(0); - } await waitForHeight(26657, height + BigInt(1)); + console.log("🧱 Started localnet at height " + height); return { home, validatorWalletName: "validator", result, process: result.child, + kill: () => killProcess(result.child, result), }; }; const waitForHeight = async (port: number, targetHeight: bigint) => { const statusCmd = `curl -s http://localhost:${port}/status`; - console.log("> " + statusCmd); + console.log("⏳ Waiting for height " + targetHeight); while (true) { try { const result = await execPromise(statusCmd); @@ -97,6 +100,7 @@ const waitForHeight = async (port: number, targetHeight: bigint) => { } catch {} await sleep(1000); } + console.log("Reached height " + targetHeight); }; export const upgradeCosmosLocalnet = async ( @@ -105,9 +109,11 @@ export const upgradeCosmosLocalnet = async ( validatorWalletName: string, home: string, ) => { + console.log("⬆️ Upgrading chain to " + newVersion); + // get height const statusCmd = `curl -s http://localhost:26657/status`; - console.log("> " + statusCmd); + console.log("⚙️ " + statusCmd); // eslint-disable-next-line no-restricted-syntax const status = JSON.parse( (await execPromise(statusCmd, { encoding: "utf-8" })).stdout, @@ -122,7 +128,7 @@ export const upgradeCosmosLocalnet = async ( --chain-id=testing --home=$HOME/.teritorid --yes -b block --deposit="100000000stake" */ const cmd = `${oldBinaryPath} tx gov submit-proposal software-upgrade "${newVersion}" --upgrade-height=${height} --title="Upgrade to ${newVersion}" --description="Upgrade to ${newVersion}" --from=${validatorWalletName} --keyring-backend=test --chain-id=testing --home=${home} --yes -b block --deposit="500000000stake" --node http://127.0.0.1:26657 -o json`; - console.log("> " + cmd); + console.log("⚙️ " + cmd); const { stdout: out } = await execPromise(cmd, { encoding: "utf-8" }); const outObj = zodTryParseJSON(zodTxResult, out); if (!outObj) { @@ -134,14 +140,14 @@ export const upgradeCosmosLocalnet = async ( --home $HOME/.teritorid -b block -y --keyring-backend test */ const voteCmd = `${oldBinaryPath} tx gov vote ${proposalId} yes --from ${validatorWalletName} --chain-id testing --home ${home} -b block -y --keyring-backend test --node http://127.0.0.1:26657`; - console.log("> " + voteCmd); + console.log("⚙️ " + voteCmd); await execPromise(voteCmd); await waitForHeight(26657, height); // check proposal status const proposalCmd = `${oldBinaryPath} query gov proposal ${proposalId} --chain-id testing --home ${home} -o json --node http://127.0.0.1:26657`; - console.log("> " + proposalCmd); + console.log("⚙️ " + proposalCmd); const { stdout: proposalOut } = await execPromise(proposalCmd, { encoding: "utf-8", }); @@ -154,6 +160,8 @@ export const upgradeCosmosLocalnet = async ( throw new Error("Proposal not passed"); } + console.log("🆙 Upgraded chain to " + newVersion); + return height; }; @@ -162,7 +170,7 @@ export const buildCosmos = async ( binaryName: string, ): Promise => { const cmd = `cd ${repoPath} && make build`; - // console.log("> " + cmd); + // console.log("⚙️ " + cmd); await new Promise((resolve, reject) => { child_process.exec(cmd, (err, stdout, stderr) => { if (err) { diff --git a/packages/scripts/integration-testing/git.ts b/packages/scripts/integration-testing/git.ts index a8d45e1c1e..01b4d3d93a 100644 --- a/packages/scripts/integration-testing/git.ts +++ b/packages/scripts/integration-testing/git.ts @@ -10,7 +10,7 @@ export const cloneRepo = async ( ): Promise => { const repoPath = await fs.mkdtemp(path.join(tmpdir(), "git-repo-")); const cmd = `git clone ${repoURL} ${repoPath} && cd ${repoPath} && git checkout ${ref}`; - // console.log("> " + cmd); + // console.log("⚙️ " + cmd); await new Promise((resolve, reject) => { child_process.exec(cmd, (err, stdout, stderr) => { if (err) { diff --git a/packages/scripts/integration-testing/simpleTest204.ts b/packages/scripts/integration-testing/simpleTest204.ts index 8ef4235744..301f482c89 100644 --- a/packages/scripts/integration-testing/simpleTest204.ts +++ b/packages/scripts/integration-testing/simpleTest204.ts @@ -2,6 +2,7 @@ import fs from "fs/promises"; import { buildBinaries, startCosmosLocalnet } from "./cosmos"; import { teritoriLocalnetNetwork } from "../../networks/teritori-localnet"; +import { killProcess } from "../lib"; import { deployTeritoriEcosystem } from "../network-setup/deployLib"; const repoURL = "https://github.com/TERITORI/teritori-chain.git"; @@ -24,8 +25,7 @@ const main = async () => { ); // stop - v204Process.kill(); - await v204Result; + killProcess(v204Process, v204Result); await fs.rm(home, { recursive: true, force: true }); }; diff --git a/packages/scripts/integration-testing/upgradeTest120to204.ts b/packages/scripts/integration-testing/upgradeTest120to204.ts index 648319958b..9a47152adc 100644 --- a/packages/scripts/integration-testing/upgradeTest120to204.ts +++ b/packages/scripts/integration-testing/upgradeTest120to204.ts @@ -23,9 +23,8 @@ const main = async () => { const { home, - result: v120Result, - process: v120Process, validatorWalletName, + kill: killv120, } = await startCosmosLocalnet(binaries["v1.2.0"]); await deployTeritoriEcosystem( @@ -40,8 +39,7 @@ const main = async () => { validatorWalletName, home, ); - v120Process.kill(); - await v120Result; + await killv120(); upgradeHeight = await runUpgrade( binaries["v1.3.0"], @@ -73,11 +71,10 @@ const main = async () => { `minimum-gas-prices = "0stake"`, ); - const { process: v204Process, result: v204Result } = - await startCosmosLocalnet(binaries["v2.0.4"], { - home, - height: upgradeHeight, - }); + const { kill: killv204 } = await startCosmosLocalnet(binaries["v2.0.4"], { + home, + height: upgradeHeight, + }); // test cosmwasm await deployTeritoriEcosystem( @@ -86,8 +83,7 @@ const main = async () => { "testnet-adm", ); - v204Process.kill(); - await v204Result; + await killv204(); await fs.rm(home, { recursive: true, force: true }); }; @@ -99,7 +95,7 @@ const runUpgrade = async ( version: string, validatorWalletName: string, ) => { - const { result, process } = await startCosmosLocalnet(binaryPath, { + const { kill } = await startCosmosLocalnet(binaryPath, { home, height, }); @@ -109,8 +105,7 @@ const runUpgrade = async ( validatorWalletName, home, ); - process.kill(); - await result; + await kill(); return upgradeHeight; }; diff --git a/packages/scripts/integration-testing/upgradeTest142to204.ts b/packages/scripts/integration-testing/upgradeTest142to204.ts index 474d87fa3a..23e8a86e72 100644 --- a/packages/scripts/integration-testing/upgradeTest142to204.ts +++ b/packages/scripts/integration-testing/upgradeTest142to204.ts @@ -20,8 +20,7 @@ const main = async () => { const { home, - result: v142Result, - process: v142Process, + kill: killv142, validatorWalletName, } = await startCosmosLocalnet(binaries["v1.4.2"]); @@ -37,8 +36,7 @@ const main = async () => { validatorWalletName, home, ); - v142Process.kill(); - await v142Result; + await killv142(); await replaceInFile( path.join(home, "config/app.toml"), @@ -47,13 +45,10 @@ const main = async () => { ); // start next version - const { result, process: v204Process } = await startCosmosLocalnet( - binaries["v2.0.4"], - { - home, - height: upgradeHeight, - }, - ); + const { kill: killv204 } = await startCosmosLocalnet(binaries["v2.0.4"], { + home, + height: upgradeHeight, + }); // test cosmwasm await deployTeritoriEcosystem( @@ -63,8 +58,7 @@ const main = async () => { ); // stop - v204Process.kill(); - await result; + await killv204(); await fs.rm(home, { recursive: true, force: true }); }; diff --git a/packages/scripts/lib.ts b/packages/scripts/lib.ts index a7c8a7e72f..6173a0b785 100644 --- a/packages/scripts/lib.ts +++ b/packages/scripts/lib.ts @@ -1,5 +1,5 @@ import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport"; -import child_process from "child_process"; +import child_process, { ChildProcess, PromiseWithChild } from "child_process"; import fs from "fs/promises"; import util from "util"; import { z } from "zod"; @@ -109,3 +109,24 @@ export const replaceInFile = async ( }; export const execPromise = util.promisify(child_process.exec); + +export const killProcess = async ( + p: ChildProcess, + r: PromiseWithChild<{ + stdout: string; + stderr: string; + }>, + timeout?: number, +) => { + console.log("🔪 Killing process"); + const innerKillProcess = async () => { + p.kill(); + await r; + }; + const startTimeout = async () => { + await sleep(timeout || 5000); + throw new Error("Timed out waiting for process to terminate"); + }; + await Promise.race([startTimeout(), innerKillProcess()]); + console.log("🔪 Process terminated"); +}; diff --git a/packages/scripts/network-setup/deployLib.ts b/packages/scripts/network-setup/deployLib.ts index a7987144ac..18fe8fdd28 100644 --- a/packages/scripts/network-setup/deployLib.ts +++ b/packages/scripts/network-setup/deployLib.ts @@ -189,7 +189,7 @@ const instantiateNameService = async ( } --node ${injectRPCPort( network.rpcEndpoint, )} --yes --keyring-backend test -o json --home ${opts.home}`; - console.log("> " + cmd); + console.log("⚙️ " + cmd); let { stdout: out } = await retry(5, async () => { return await execPromise(cmd, { encoding: "utf-8", @@ -224,7 +224,7 @@ const instantiateContract = async ( )} --yes --keyring-backend test -o json --label ${sqh( label, )} --admin ${admin} --home ${opts.home}`; - console.log("> " + cmd); + console.log("⚙️ " + cmd); let { stdout: out } = await retry( 5, async () => @@ -257,7 +257,7 @@ const storeWASM = async ( } --node ${injectRPCPort( network.rpcEndpoint, )} --yes --keyring-backend test -o json --home ${opts.home}`; - console.log("> " + cmd); + console.log("⚙️ " + cmd); let { stdout: out } = await retry(5, async () => { return await execPromise(cmd, { encoding: "utf-8", @@ -292,6 +292,7 @@ const getTx = async (networkId: string, txhash: string, timeout?: number) => { await sleep(timeout || 20000); return undefined; }; + console.log("⏳ Waiting for tx '" + txhash + "'"); const tx = await Promise.race([startTimeout(), innerGetTx()]); if (!tx) { throw new Error("Timed out waiting for tx '" + txhash + "'"); @@ -306,6 +307,7 @@ const getTx = async (networkId: string, txhash: string, timeout?: number) => { JSON.stringify(tx, null, 2), ); } + console.log("Tx '" + txhash + "' found"); return tx; }; diff --git a/packages/scripts/network-setup/restoreContract.ts b/packages/scripts/network-setup/restoreContract.ts index 61ab1a60ab..078539fcbc 100644 --- a/packages/scripts/network-setup/restoreContract.ts +++ b/packages/scripts/network-setup/restoreContract.ts @@ -51,7 +51,7 @@ const main = async () => { } --node ${injectRPCPort(destinationNetwork.rpcEndpoint)} -o json${ keyringBackend ? ` --keyring-backend ${keyringBackend}` : "" }`; - console.log("> " + cmd); + console.log("⚙️ " + cmd); const out = child_process.execSync(cmd, { stdio: ["inherit", "pipe", "inherit"], encoding: "utf-8",