mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
WARNING: This PR changes the kurtosis package to use the one from upstream, not our fork, as it was not working at the moment. This should be changed when fixed. In this PR: 1. Turn `launch-kurtosis` script into a CLI, which parses parameters and can interactively run multiple steps. 2. Separate steps of such CLI into their own scripts. 1. New script created `launch-kurtosis`, which detects if an enclave is running and prompts to relaunch it if it is. 2. New script created `deploy-contracts` to deploy all contracts. It can optionally verify them as well. 3. Each step can be interactively opted in/out, or choose whether to run it via CLI params. 4. The CLI offers a help command as well. 5. Cleanup logs of CLI. Logs of internal commands ran can be printed with LOG_LEVEL=debug. In case of error, they are always printed out.
190 lines
6 KiB
TypeScript
190 lines
6 KiB
TypeScript
import { $ } from "bun";
|
|
import invariant from "tiny-invariant";
|
|
import chalk from "chalk";
|
|
import { logger, printDivider, printHeader } from "utils";
|
|
import sendTxn from "./send-txn";
|
|
import { launchKurtosis } from "./launch-kurtosis";
|
|
import { deployContracts } from "./deploy-contracts";
|
|
|
|
interface ScriptOptions {
|
|
verified: boolean;
|
|
launchKurtosis?: boolean;
|
|
deployContracts?: boolean;
|
|
help?: boolean;
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
|
|
// Parse command-line arguments
|
|
const options: ScriptOptions = {
|
|
verified: args.includes("--verified"),
|
|
launchKurtosis: parseFlag(args, "launchKurtosis"),
|
|
deployContracts: parseFlag(args, "deploy-contracts"),
|
|
help: args.includes("--help") || args.includes("-h")
|
|
};
|
|
|
|
// Show help menu if requested
|
|
if (options.help) {
|
|
printHelp();
|
|
return;
|
|
}
|
|
|
|
logger.info(`Running with options: ${getOptionsString(options)}`);
|
|
|
|
const timeStart = performance.now();
|
|
|
|
printHeader("Environment Checks");
|
|
|
|
await checkDependencies();
|
|
|
|
// Clean up and launch Kurtosis enclave
|
|
const { services } = await launchKurtosis({
|
|
launchKurtosis: options.launchKurtosis
|
|
});
|
|
|
|
// Send test transaction
|
|
printHeader("Setting Up Blockchain");
|
|
const privateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; // Anvil test acc1
|
|
const networkRpcUrl = services.find((s) => s.service === "reth-1-rpc")?.url;
|
|
invariant(networkRpcUrl, "❌ Network RPC URL not found");
|
|
|
|
logger.info("💸 Sending test transaction...");
|
|
await sendTxn(privateKey, networkRpcUrl);
|
|
|
|
printDivider();
|
|
|
|
// Display service information in a clean table
|
|
printHeader("Service Endpoints");
|
|
|
|
console.table(
|
|
services
|
|
.filter((s) => ["reth-1-rpc", "reth-2-rpc", "blockscout-backend", "dora"].includes(s.service))
|
|
.concat([
|
|
{ service: "blockscout", port: "3000", url: "http://127.0.0.1:3000" },
|
|
{ service: "kurtosis-web", port: "9711", url: "http://127.0.0.1:9711" }
|
|
])
|
|
);
|
|
|
|
printDivider();
|
|
|
|
// Show completion information
|
|
const timeEnd = performance.now();
|
|
const minutes = ((timeEnd - timeStart) / (1000 * 60)).toFixed(1);
|
|
|
|
logger.success(`Kurtosis network started successfully in ${minutes} minutes`);
|
|
|
|
printDivider();
|
|
|
|
// Deploy contracts using the extracted function
|
|
const blockscoutBackendUrl = services.find((s) => s.service === "blockscout-backend")?.url;
|
|
await deployContracts({
|
|
rpcUrl: networkRpcUrl,
|
|
verified: options.verified,
|
|
blockscoutBackendUrl,
|
|
deployContracts: options.deployContracts
|
|
});
|
|
}
|
|
|
|
// Helper function to check all dependencies at once
|
|
const checkDependencies = async (): Promise<void> => {
|
|
if (!(await checkKurtosisInstalled())) {
|
|
logger.error("Kurtosis CLI is required to be installed: https://docs.kurtosis.com/install");
|
|
throw Error("❌ Kurtosis CLI application not found.");
|
|
}
|
|
|
|
logger.success("Kurtosis CLI found");
|
|
|
|
if (!(await checkDockerRunning())) {
|
|
logger.error("Is Docker Running? Unable to make connection to docker daemon");
|
|
throw Error("❌ Error connecting to Docker");
|
|
}
|
|
|
|
logger.success("Docker is running");
|
|
|
|
if (!(await checkForgeInstalled())) {
|
|
logger.error("Is foundry installed? https://book.getfoundry.sh/getting-started/installation");
|
|
throw Error("❌ forge binary not found in PATH");
|
|
}
|
|
|
|
logger.success("Forge is installed");
|
|
};
|
|
|
|
const checkKurtosisInstalled = async (): Promise<boolean> => {
|
|
const { exitCode, stderr, stdout } = await $`kurtosis version`.nothrow().quiet();
|
|
if (exitCode !== 0) {
|
|
logger.error(stderr.toString());
|
|
return false;
|
|
}
|
|
logger.debug(stdout.toString());
|
|
return true;
|
|
};
|
|
|
|
const checkDockerRunning = async (): Promise<boolean> => {
|
|
const { exitCode, stderr, stdout } = await $`docker system info`.nothrow().quiet();
|
|
if (exitCode !== 0) {
|
|
logger.error(stderr.toString());
|
|
return false;
|
|
}
|
|
logger.debug(stdout.toString());
|
|
return true;
|
|
};
|
|
|
|
const checkForgeInstalled = async (): Promise<boolean> => {
|
|
const { exitCode, stderr, stdout } = await $`forge --version`.nothrow().quiet();
|
|
if (exitCode !== 0) {
|
|
logger.error(stderr.toString());
|
|
return false;
|
|
}
|
|
logger.debug(stdout.toString());
|
|
return true;
|
|
};
|
|
|
|
// Helper function to format options as a string
|
|
function getOptionsString(options: ScriptOptions): string {
|
|
const optionStrings: string[] = [];
|
|
if (options.verified) optionStrings.push("verified");
|
|
if (options.launchKurtosis !== undefined)
|
|
optionStrings.push(`launchKurtosis=${options.launchKurtosis}`);
|
|
if (options.deployContracts !== undefined)
|
|
optionStrings.push(`deployContracts=${options.deployContracts}`);
|
|
return optionStrings.length ? optionStrings.join(", ") : "no options";
|
|
}
|
|
|
|
// Print help menu
|
|
function printHelp(): void {
|
|
console.log(chalk.bold.cyan("\nDatahaven Kurtosis Startup Script"));
|
|
console.log(chalk.gray("=".repeat(40)));
|
|
console.log(`
|
|
${chalk.yellow("Available Options:")}
|
|
|
|
${chalk.green("--verified")} Use contract verification via Blockscout
|
|
${chalk.green("--launchKurtosis")} Clean and launch Kurtosis enclave if already running
|
|
${chalk.green("--no-launchKurtosis")} Keep existing Kurtosis enclave if already running
|
|
${chalk.green("--deploy-contracts")} Deploy smart contracts after Kurtosis starts
|
|
${chalk.green("--no-deploy-contracts")} Skip smart contract deployment
|
|
${chalk.green("--help, -h")} Show this help menu
|
|
|
|
${chalk.yellow("Examples:")}
|
|
${chalk.gray("# Start with interactive prompts")}
|
|
bun run start-kurtosis
|
|
|
|
${chalk.gray("# Start with verification and automatic redeploy")}
|
|
bun run start-kurtosis --verified --redeploy
|
|
|
|
${chalk.gray("# Start without deploying contracts")}
|
|
bun run start-kurtosis --no-deploy-contracts
|
|
`);
|
|
}
|
|
|
|
// Parse and handle boolean flags with negations
|
|
function parseFlag(args: string[], flagName: string): boolean | undefined {
|
|
const positiveFlag = `--${flagName}`;
|
|
const negativeFlag = `--no-${flagName}`;
|
|
|
|
if (args.includes(positiveFlag)) return true;
|
|
if (args.includes(negativeFlag)) return false;
|
|
return undefined;
|
|
}
|
|
|
|
main();
|