diff --git a/.github/workflows/task-e2e.yml b/.github/workflows/task-e2e.yml index a6a50279..ce0cbde1 100644 --- a/.github/workflows/task-e2e.yml +++ b/.github/workflows/task-e2e.yml @@ -71,6 +71,14 @@ jobs: with: name: datahaven-node-${{ inputs.binary-hash }} path: operator/target/release/ + + - name: Download snowbridge binary + run: | + docker create --name temp moonsonglabs/snowbridge-relayer:latest + mkdir -p tmp/bin + docker cp temp:/usr/local/bin/snowbridge-relay tmp/bin/ + chmod +x tmp/bin/snowbridge-relay + - run: tmp/bin/snowbridge-relay --help - run: chmod +x ../operator/target/release/datahaven-node - run: ../operator/target/release/datahaven-node --help diff --git a/test/cli/handlers/launch/checks.ts b/test/cli/handlers/launch/checks.ts index 8c1b8c0c..8b424f47 100644 --- a/test/cli/handlers/launch/checks.ts +++ b/test/cli/handlers/launch/checks.ts @@ -1,8 +1,10 @@ import { $ } from "bun"; -import { logger } from "utils"; +import { logger, printDivider, printHeader } from "utils"; // ===== Checks ===== export const checkDependencies = async (): Promise => { + printHeader("Environment Checks"); + if (!(await checkKurtosisInstalled())) { logger.error("Kurtosis CLI is required to be installed: https://docs.kurtosis.com/install"); throw Error("❌ Kurtosis CLI application not found."); @@ -23,6 +25,7 @@ export const checkDependencies = async (): Promise => { } logger.success("Forge is installed"); + printDivider(); }; const checkKurtosisInstalled = async (): Promise => { diff --git a/test/cli/handlers/launch/datahaven.ts b/test/cli/handlers/launch/datahaven.ts index 92421a11..2d068479 100644 --- a/test/cli/handlers/launch/datahaven.ts +++ b/test/cli/handlers/launch/datahaven.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import { $ } from "bun"; import invariant from "tiny-invariant"; -import { logger, printHeader } from "utils"; +import { confirmWithTimeout, logger, printDivider, printHeader } from "utils"; import type { LaunchOptions } from "."; import type { LaunchedNetwork } from "./launchedNetwork"; @@ -21,11 +21,39 @@ const COMMON_LAUNCH_ARGS = [ const AUTHORITY_IDS = ["alice", "bob", "charlie", "dave", "eve"]; // TODO: This is very rough and will need something more substantial when we know what we want! -export const performDatahavenOperations = async ( +/** + * Launches a DataHaven solochain network for testing. + * + * @param options - Configuration options for launching the network. + * @param launchedNetwork - An instance of LaunchedNetwork to track the network's state. + */ +export const launchDataHavenSolochain = async ( options: LaunchOptions, launchedNetwork: LaunchedNetwork ) => { - printHeader("Starting Datahaven Network"); + printHeader("Starting DataHaven Network"); + + let shouldLaunchDataHaven = options.datahaven; + if (shouldLaunchDataHaven === undefined) { + shouldLaunchDataHaven = await confirmWithTimeout( + "Do you want to launch the DataHaven network?", + true, + 10 + ); + } else { + logger.info( + `Using flag option: ${shouldLaunchDataHaven ? "will launch" : "will not launch"} DataHaven network` + ); + } + + if (!shouldLaunchDataHaven) { + logger.info("Skipping DataHaven network launch. Done!"); + printDivider(); + return; + } + + // Kill any pre-existing datahaven processes if they exist + await $`pkill datahaven`.nothrow().quiet(); invariant(options.datahavenBinPath, "❌ Datahaven binary path not defined"); invariant( @@ -59,7 +87,7 @@ export const performDatahavenOperations = async ( let completed = false; const file = Bun.file(logFilePath); - for (let i = 0; i < 10; i++) { + for (let i = 0; i < 60; i++) { const pattern = "Running JSON-RPC server: addr=127.0.0.1:"; const blob = await file.text(); logger.debug(`Blob: ${blob}`); diff --git a/test/cli/handlers/launch/index.ts b/test/cli/handlers/launch/index.ts index f7e1267c..8d9f6852 100644 --- a/test/cli/handlers/launch/index.ts +++ b/test/cli/handlers/launch/index.ts @@ -2,18 +2,12 @@ import type { Command } from "@commander-js/extra-typings"; import { deployContracts } from "scripts/deploy-contracts"; import sendTxn from "scripts/send-txn"; import invariant from "tiny-invariant"; -import { - ANVIL_FUNDED_ACCOUNTS, - getPortFromKurtosis, - logger, - printDivider, - printHeader -} from "utils"; +import { ANVIL_FUNDED_ACCOUNTS, getPortFromKurtosis, logger } from "utils"; import { checkDependencies } from "./checks"; -import { performDatahavenOperations } from "./datahaven"; +import { launchDataHavenSolochain } from "./datahaven"; import { launchKurtosis } from "./kurtosis"; import { LaunchedNetwork } from "./launchedNetwork"; -import { performRelayerOperations } from "./relayer"; +import { launchRelayers } from "./relayer"; import { performSummaryOperations } from "./summary"; import { performValidatorOperations } from "./validator"; @@ -51,39 +45,26 @@ const launchFunction = async (options: LaunchOptions, launchedNetwork: LaunchedN const timeStart = performance.now(); - printHeader("Environment Checks"); - await checkDependencies(); - logger.trace("Launching Kurtosis enclave"); - await launchKurtosis(options); - logger.trace("Kurtosis enclave launched"); + await launchDataHavenSolochain(options, launchedNetwork); + + await launchKurtosis(options); - logger.trace("Send test transaction"); - printHeader("Setting Up Blockchain"); logger.debug(`Using account ${ANVIL_FUNDED_ACCOUNTS[1].publicKey}`); const privateKey = ANVIL_FUNDED_ACCOUNTS[1].privateKey; const rethPublicPort = await getPortFromKurtosis("el-1-reth-lighthouse", "rpc"); const networkRpcUrl = `http://127.0.0.1:${rethPublicPort}`; invariant(networkRpcUrl, "❌ Network RPC URL not found"); - logger.info("💸 Sending test transaction..."); await sendTxn(privateKey, networkRpcUrl); - printDivider(); - - logger.trace("Show completion information"); - const timeEnd = performance.now(); - const minutes = ((timeEnd - timeStart) / (1000 * 60)).toFixed(1); - - logger.success(`Kurtosis network started successfully in ${minutes} minutes`); - - logger.trace("Deploy contracts using the extracted function"); let blockscoutBackendUrl: string | undefined = undefined; if (options.blockscout === true) { const blockscoutPublicPort = await getPortFromKurtosis("blockscout", "http"); blockscoutBackendUrl = `http://127.0.0.1:${blockscoutPublicPort}`; + logger.trace("Blockscout backend URL:", blockscoutBackendUrl); } else if (options.verified) { logger.warn( "âš ī¸ Contract verification (--verified) requested, but Blockscout is disabled (--no-blockscout). Verification will be skipped." @@ -97,34 +78,20 @@ const launchFunction = async (options: LaunchOptions, launchedNetwork: LaunchedN deployContracts: options.deployContracts }); - if (contractsDeployed) { - await performValidatorOperations(options, networkRpcUrl); - } else if (options.setupValidators || options.fundValidators) { - logger.warn( - "âš ī¸ Validator operations requested but contracts were not deployed. Skipping validator operations." - ); - } - if (options.datahaven) { - await performDatahavenOperations(options, launchedNetwork); - } + await performValidatorOperations(options, networkRpcUrl, contractsDeployed); - if (options.relayer) { - await performRelayerOperations(options, launchedNetwork); - } - - printDivider(); + await launchRelayers(options, launchedNetwork); performSummaryOperations(options, launchedNetwork); const fullEnd = performance.now(); const fullMinutes = ((fullEnd - timeStart) / (1000 * 60)).toFixed(1); - logger.info(`Launch function completed successfully in ${fullMinutes} minutes`); + logger.success(`Launch function completed successfully in ${fullMinutes} minutes`); }; export const launch = async (options: LaunchOptions) => { const run = new LaunchedNetwork(); try { await launchFunction(options, run); - logger.success("Launch script completed successfully"); } finally { await run.cleanup(); } diff --git a/test/cli/handlers/launch/kurtosis.ts b/test/cli/handlers/launch/kurtosis.ts index 6eff88f7..5cd4525f 100644 --- a/test/cli/handlers/launch/kurtosis.ts +++ b/test/cli/handlers/launch/kurtosis.ts @@ -20,12 +20,15 @@ import { parse, stringify } from "yaml"; export const launchKurtosis = async ( options: LaunchOptions = {} ): Promise> => { + printHeader("Starting Kurtosis Network"); + if ((await checkKurtosisRunning()) && !options.alwaysClean) { logger.info("â„šī¸ Kurtosis network is already running."); logger.trace("Checking if launchKurtosis option was set via flags"); if (options.launchKurtosis === false) { - logger.info("Keeping existing Kurtosis enclave. Exiting..."); + logger.info("Keeping existing Kurtosis enclave."); + printDivider(); return getServicesFromKurtosis(); } @@ -40,7 +43,8 @@ export const launchKurtosis = async ( ); if (!shouldRelaunch) { - logger.info("Keeping existing Kurtosis enclave. Exiting..."); + logger.info("Keeping existing Kurtosis enclave."); + printDivider(); return getServicesFromKurtosis(); } @@ -48,8 +52,6 @@ export const launchKurtosis = async ( } } - printHeader("Starting Kurtosis Network"); - if (!options.skipCleaning) { logger.info("🧹 Cleaning up Docker and Kurtosis environments..."); logger.debug(await $`kurtosis enclave stop datahaven-ethereum`.nothrow().text()); @@ -69,7 +71,7 @@ export const launchKurtosis = async ( const configFile = await modifyConfig(options, "configs/kurtosis/minimal.yaml"); - logger.info(`Using Kurtosis config file: ${configFile}`); + logger.info(`âš™ī¸ Using Kurtosis config file: ${configFile}`); const { stderr, stdout, exitCode } = await $`kurtosis run github.com/ethpandaops/ethereum-package --args-file ${configFile} --enclave datahaven-ethereum` @@ -85,6 +87,7 @@ export const launchKurtosis = async ( logger.info("🔍 Gathering Kurtosis public ports..."); const services = await getServicesFromKurtosis(); + logger.success("Kurtosis network started successfully"); printDivider(); return services; diff --git a/test/cli/handlers/launch/launchedNetwork.ts b/test/cli/handlers/launch/launchedNetwork.ts index fb6aae48..ee3bc2be 100644 --- a/test/cli/handlers/launch/launchedNetwork.ts +++ b/test/cli/handlers/launch/launchedNetwork.ts @@ -43,7 +43,7 @@ export class LaunchedNetwork { async cleanup() { for (const process of this.processes) { - logger.info(`Process is still running: ${process.pid}`); + logger.debug(`Process is still running: ${process.pid}`); } for (const fd of this.fileDescriptors) { diff --git a/test/cli/handlers/launch/relayer.ts b/test/cli/handlers/launch/relayer.ts index ff875118..acd4f1b6 100644 --- a/test/cli/handlers/launch/relayer.ts +++ b/test/cli/handlers/launch/relayer.ts @@ -6,10 +6,12 @@ import { ANVIL_FUNDED_ACCOUNTS, type RelayerType, SUBSTRATE_FUNDED_ACCOUNTS, + confirmWithTimeout, getPortFromKurtosis, logger, parseDeploymentsFile, parseRelayConfig, + printDivider, printHeader } from "utils"; import type { LaunchOptions } from "."; @@ -22,12 +24,36 @@ type RelayerSpec = { pk: { type: "ethereum" | "substrate"; value: string }; }; -export const performRelayerOperations = async ( - options: LaunchOptions, - launchedNetwork: LaunchedNetwork -) => { +/** + * Launches Snowbridge relayers for the DataHaven network. + * + * @param options - Configuration options for launching the relayers. + * @param launchedNetwork - An instance of LaunchedNetwork to track the network's state. + */ +export const launchRelayers = async (options: LaunchOptions, launchedNetwork: LaunchedNetwork) => { printHeader("Starting Snowbridge Relayers"); - logger.info("Preparing to generate configs"); + + let shouldLaunchRelayers = options.relayer; + if (shouldLaunchRelayers === undefined) { + shouldLaunchRelayers = await confirmWithTimeout( + "Do you want to launch the Snowbridge relayers?", + true, + 10 + ); + } else { + logger.info( + `Using flag option: ${shouldLaunchRelayers ? "will launch" : "will not launch"} Snowbridge relayers` + ); + } + + if (!shouldLaunchRelayers) { + logger.info("Skipping Snowbridge relayers launch. Done!"); + printDivider(); + return; + } + + // Kill any pre-existing relayer processes if they exist + await $`pkill snowbridge-relay`.nothrow().quiet(); const anvilDeployments = await parseDeploymentsFile(); const beefyClientAddress = anvilDeployments.BeefyClient; @@ -155,4 +181,5 @@ export const performRelayerOperations = async ( } logger.success("Snowbridge relayers started"); + printDivider(); }; diff --git a/test/cli/handlers/launch/summary.ts b/test/cli/handlers/launch/summary.ts index 82edf164..4fbdddcd 100644 --- a/test/cli/handlers/launch/summary.ts +++ b/test/cli/handlers/launch/summary.ts @@ -7,23 +7,21 @@ export const performSummaryOperations = async ( options: LaunchOptions, launchedNetwork: LaunchedNetwork ) => { - logger.trace("Display service information in a clean table"); printHeader("Service Endpoints"); - logger.trace("Filter services to display based on blockscout option"); const servicesToDisplay = BASE_SERVICES; if (options.blockscout === true) { servicesToDisplay.push(...["blockscout", "blockscout-frontend"]); } - if (options.datahaven === true) { - const dhNodes = launchedNetwork.getDHNodes(); - for (const { id } of dhNodes) { - servicesToDisplay.push(`datahaven-${id}`); - } + const dhNodes = launchedNetwork.getDHNodes(); + for (const { id } of dhNodes) { + servicesToDisplay.push(`datahaven-${id}`); } + logger.trace("Services to display", servicesToDisplay); + const displayData: { service: string; ports: Record; url: string }[] = []; for (const service of servicesToDisplay) { logger.debug(`Checking service: ${service}`); @@ -106,5 +104,4 @@ export const performSummaryOperations = async ( } console.table(displayData); - logger.debug("Summary completed successfully"); }; diff --git a/test/cli/handlers/launch/validator.ts b/test/cli/handlers/launch/validator.ts index b1b87351..1c2015f6 100644 --- a/test/cli/handlers/launch/validator.ts +++ b/test/cli/handlers/launch/validator.ts @@ -1,16 +1,16 @@ import { fundValidators } from "scripts/fund-validators"; import { setupValidators } from "scripts/setup-validators"; import { updateValidatorSet } from "scripts/update-validator-set"; -import { confirmWithTimeout, logger } from "utils"; +import { confirmWithTimeout, logger, printDivider, printHeader } from "utils"; import type { LaunchOptions } from ".."; -export const performValidatorOperations = async (options: LaunchOptions, networkRpcUrl: string) => { - logger.trace("Set up validators using the extracted function"); +export const performValidatorOperations = async ( + options: LaunchOptions, + networkRpcUrl: string, + contractsDeployed: boolean +) => { + // If not specified, prompt for funding let shouldFundValidators = options.fundValidators; - let shouldSetupValidators = options.setupValidators; - let shouldUpdateValidatorSet = options.updateValidatorSet; - - logger.trace("If not specified, prompt for funding"); if (shouldFundValidators === undefined) { shouldFundValidators = await confirmWithTimeout( "Do you want to fund validators with tokens and ETH?", @@ -23,7 +23,23 @@ export const performValidatorOperations = async (options: LaunchOptions, network ); } - logger.trace("If not specified, prompt for setup"); + if (shouldFundValidators) { + if (!contractsDeployed) { + logger.warn( + "âš ī¸ Funding validators but contracts were not deployed in this CLI run. Could have unexpected results." + ); + } + + await fundValidators({ + rpcUrl: networkRpcUrl + }); + } else { + logger.debug("Skipping validator funding"); + printDivider(); + } + + // If not specified, prompt for setup + let shouldSetupValidators = options.setupValidators; if (shouldSetupValidators === undefined) { shouldSetupValidators = await confirmWithTimeout( "Do you want to register validators in EigenLayer?", @@ -36,40 +52,47 @@ export const performValidatorOperations = async (options: LaunchOptions, network ); } - logger.trace("If not specified, prompt for update"); - if (shouldUpdateValidatorSet === undefined) { - shouldUpdateValidatorSet = await confirmWithTimeout( - "Do you want to update the validator set on the substrate chain?", - true, - 10 - ); - } else { - logger.info( - `Using flag option: ${shouldUpdateValidatorSet ? "will update" : "will not update"} validator set` - ); - } - - if (shouldFundValidators) { - await fundValidators({ - rpcUrl: networkRpcUrl - }); - } else { - logger.info("Skipping validator funding"); - } - if (shouldSetupValidators) { + if (!contractsDeployed) { + logger.warn( + "âš ī¸ Setting up validators but contracts were not deployed in this CLI run. Could have unexpected results." + ); + } + await setupValidators({ rpcUrl: networkRpcUrl }); + // If not specified, prompt for update + let shouldUpdateValidatorSet = options.updateValidatorSet; + if (shouldUpdateValidatorSet === undefined) { + shouldUpdateValidatorSet = await confirmWithTimeout( + "Do you want to update the validator set on the substrate chain?", + true, + 10 + ); + } else { + logger.info( + `Using flag option: ${shouldUpdateValidatorSet ? "will update" : "will not update"} validator set` + ); + } + if (shouldUpdateValidatorSet) { + if (!contractsDeployed) { + logger.warn( + "âš ī¸ Updating validator set but contracts were not deployed in this CLI run. Could have unexpected results." + ); + } + await updateValidatorSet({ rpcUrl: networkRpcUrl }); } else { - logger.info("Skipping validator set update"); + logger.debug("Skipping validator set update"); + printDivider(); } } else { - logger.info("Skipping validator setup"); + logger.debug("Skipping validator setup"); + printDivider(); } }; diff --git a/test/cli/index.ts b/test/cli/index.ts index 0b9ae985..c7bc17ac 100644 --- a/test/cli/index.ts +++ b/test/cli/index.ts @@ -14,6 +14,7 @@ function parseIntValue(value: string): number { // So far we only have the launch command // we can expand this to more commands in the future const program = new Command() + .option("--datahaven", "Enable Datahaven network to be launched") .option("-l, --launch-kurtosis", "Launch Kurtosis") .option("-d, --deploy-contracts", "Deploy smart contracts") .option("-f, --fund-validators", "Fund validators") @@ -24,17 +25,16 @@ const program = new Command() .option("--no-update-validator-set", "Skip update validator set") .option("-b, --blockscout", "Enable Blockscout") .option("--slot-time ", "Set slot time in seconds", parseIntValue) - .option("--datahaven", "Enable Datahaven network to be launched") .option("--kurtosis-network-args ", "CustomKurtosis network args") + .option("-v, --verified", "Verify smart contracts with Blockscout") + .option("--always-clean", "Always clean Kurtosis", false) + .option("-q, --skip-cleaning", "Skip cleaning Kurtosis") + .option("-r, --relayer", "Enable Relayer") .option( "--datahaven-bin-path ", "Path to the datahaven binary", "../operator/target/release/datahaven-node" ) - .option("-v, --verified", "Verify smart contracts with Blockscout") - .option("--always-clean", "Always clean Kurtosis", false) - .option("-q, --skip-cleaning", "Skip cleaning Kurtosis") - .option("-r, --relayer", "Enable Relayer") .option( "-p, --relayer-bin-path ", "Path to the relayer binary", diff --git a/test/configs/snowbridge/beacon-relay.json b/test/configs/snowbridge/beacon-relay.json index 2ba9511a..eb7000a3 100644 --- a/test/configs/snowbridge/beacon-relay.json +++ b/test/configs/snowbridge/beacon-relay.json @@ -1,29 +1,29 @@ { - "source": { - "beacon": { - "endpoint": "http://127.0.0.1:32791", - "stateEndpoint": "http://127.0.0.1:32791", - "spec": { - "syncCommitteeSize": 512, - "slotsInEpoch": 32, - "epochsPerSyncCommitteePeriod": 256, - "forkVersions": { - "deneb": 0, - "electra": 0 - } - }, - "datastore": { - "location": "/home/timbo/workspace/moonsong/datahaven/test/tmp/facu-test", - "maxEntries": 100 - } + "source": { + "beacon": { + "endpoint": "http://127.0.0.1:33030", + "stateEndpoint": "http://127.0.0.1:33030", + "spec": { + "syncCommitteeSize": 512, + "slotsInEpoch": 32, + "epochsPerSyncCommitteePeriod": 4, + "forkVersions": { + "deneb": 0, + "electra": 18446744073709551615 } - }, - "sink": { - "parachain": { - "endpoint": "ws://127.0.0.1:9944", - "maxWatchedExtrinsics": 8, - "headerRedundancy": 20 - }, - "updateSlotInterval": 30 + }, + "datastore": { + "location": "/Users/facundofarall/Desktop/Moonsong/datahaven/test/tmp/facu-test", + "maxEntries": 100 + } } + }, + "sink": { + "parachain": { + "endpoint": "ws://127.0.0.1:9944", + "maxWatchedExtrinsics": 8, + "headerRedundancy": 20 + }, + "updateSlotInterval": 30 + } } diff --git a/test/package.json b/test/package.json index 33c4a7de..6ae2acae 100644 --- a/test/package.json +++ b/test/package.json @@ -11,9 +11,9 @@ "generate:wagmi": "wagmi generate", "generate:snowbridge-cfgs": "bun -e \"import {generateSnowbridgeConfigs} from './scripts/gen-snowbridge-cfgs.ts'; await generateSnowbridgeConfigs()\"", "start:e2e:verified": "bun cli --verified --blockscout --deploy-contracts --setup-validators --update-validator-set --fund-validators --slot-time 1", - "start:e2e:ci": "bun cli -d --setup-validators --update-validator-set --fund-validators --always-clean --slot-time 2", + "start:e2e:ci": "bun cli -d --setup-validators --update-validator-set --fund-validators --always-clean --slot-time 2 --datahaven --relayer", "start:e2e:minrelayer": "bun cli --relayer -d --no-setup-validators --no-update-validator-set --no-fund-validators --datahaven", - "stop:e2e": "pkill datahaven ; kurtosis enclave stop datahaven-ethereum && kurtosis clean && kurtosis engine stop && docker container prune -f", + "stop:e2e": "pkill datahaven ; pkill snowbridge-relay ; kurtosis enclave stop datahaven-ethereum && kurtosis clean && kurtosis engine stop && docker container prune -f", "stop:e2e:verified": "bun stop:e2e", "stop:e2e:minimal": "bun stop:e2e", "stop:e2e:quick": "kurtosis enclave stop datahaven-ethereum", diff --git a/test/resources/datahaven-integration-test-flow.md b/test/resources/datahaven-integration-test-flow.md index 8f1ecdf4..0ff952bc 100644 --- a/test/resources/datahaven-integration-test-flow.md +++ b/test/resources/datahaven-integration-test-flow.md @@ -93,6 +93,7 @@ In this phase, we register validators as operators in EigenLayer and sync the va - Configures validator addresses and permissions 3. **Sync Validator Set to DataHaven** + - Use `update-validator-set.ts` script to sync validators - Calls `sendNewValidatorSet` function in the DataHavenServiceManager contract - Sends validator set through Snowbridge Gateway to DataHaven solochain diff --git a/test/scripts/deploy-contracts.ts b/test/scripts/deploy-contracts.ts index 39dddc9d..4b0b836a 100644 --- a/test/scripts/deploy-contracts.ts +++ b/test/scripts/deploy-contracts.ts @@ -1,6 +1,12 @@ import { $ } from "bun"; import invariant from "tiny-invariant"; -import { confirmWithTimeout, logger, printHeader, runShellCommandWithLogger } from "utils"; +import { + confirmWithTimeout, + logger, + printDivider, + printHeader, + runShellCommandWithLogger +} from "utils"; interface DeployContractsOptions { rpcUrl: string; @@ -38,6 +44,8 @@ export const deployContracts = async (options: DeployContractsOptions): Promise< if (!shouldDeployContracts) { logger.info("Skipping contract deployment. Done!"); + printDivider(); + return false; } @@ -76,6 +84,8 @@ export const deployContracts = async (options: DeployContractsOptions): Promise< await runShellCommandWithLogger(deployCommand, { cwd: "../contracts" }); logger.success("Contracts deployed successfully"); + printDivider(); + return true; }; diff --git a/test/scripts/fund-validators.ts b/test/scripts/fund-validators.ts index 2f48a7f8..c2feef5e 100644 --- a/test/scripts/fund-validators.ts +++ b/test/scripts/fund-validators.ts @@ -3,7 +3,7 @@ import path from "node:path"; // Script to fund validators with tokens and ETH for local testing import { $ } from "bun"; import invariant from "tiny-invariant"; -import { logger, printHeader } from "../utils/index"; +import { logger, printDivider, printHeader } from "../utils/index"; interface FundValidatorsOptions { rpcUrl: string; @@ -167,8 +167,9 @@ export const fundValidators = async (options: FundValidatorsOptions): Promise => { - const { - rpcUrl, - validatorsConfig, - executeSignup, - networkName = "anvil", - deploymentPath - } = options; - - // Check if executeSignup option was set via flags, or prompt if not - let shouldExecuteSignup = executeSignup; - if (shouldExecuteSignup === undefined) { - shouldExecuteSignup = await confirmWithTimeout( - "Do you want to register validators in EigenLayer?", - true, - 10 - ); - } else { - logger.info( - `Using flag option: ${shouldExecuteSignup ? "will register" : "will not register"} validators` - ); - } - - if (!shouldExecuteSignup) { - logger.info("Skipping validator setup. Done!"); - return false; - } + const { rpcUrl, validatorsConfig, networkName = "anvil" } = options; printHeader("Setting Up DataHaven Validators"); @@ -130,11 +116,13 @@ export const setupValidators = async (options: SetupValidatorsOptions): Promise< const signupCommand = `forge script script/transact/SignUpValidator.s.sol --rpc-url ${rpcUrl} --broadcast --no-rpc-rate-limit --non-interactive`; logger.debug(`Running command: ${signupCommand}`); - await runShellCommandWithLogger(signupCommand, { env, cwd: "../contracts" }); + await runShellCommandWithLogger(signupCommand, { env, cwd: "../contracts", logLevel: "debug" }); logger.success(`Successfully registered validator ${validator.publicKey}`); } + printDivider(); + return true; }; diff --git a/test/scripts/update-validator-set.ts b/test/scripts/update-validator-set.ts index 01d04f7d..53d497da 100644 --- a/test/scripts/update-validator-set.ts +++ b/test/scripts/update-validator-set.ts @@ -3,7 +3,7 @@ import path from "node:path"; // Update validator set on DataHaven substrate chain import { $ } from "bun"; import invariant from "tiny-invariant"; -import { logger, printHeader } from "../utils/index"; +import { logger, printDivider, printHeader } from "../utils/index"; interface UpdateValidatorSetOptions { rpcUrl: string; @@ -56,7 +56,7 @@ export const updateValidatorSet = async (options: UpdateValidatorSetOptions): Pr logger.debug(`Running command: ${sendCommand}`); - const { exitCode, stderr } = await $`sh -c ${sendCommand}`.nothrow(); + const { exitCode, stderr } = await $`sh -c ${sendCommand}`.nothrow().quiet(); if (exitCode !== 0) { logger.error(`Failed to send validator set: ${stderr.toString()}`); @@ -83,6 +83,8 @@ export const updateValidatorSet = async (options: UpdateValidatorSetOptions): Pr } */ + printDivider(); + return true; }; diff --git a/test/utils/shell.ts b/test/utils/shell.ts index 646634ec..a379dc6b 100644 --- a/test/utils/shell.ts +++ b/test/utils/shell.ts @@ -2,11 +2,13 @@ import { existsSync } from "node:fs"; import { spawn } from "bun"; import { logger } from "./logger"; +export type LogLevel = "info" | "debug" | "error" | "warn"; + export const runShellCommandWithLogger = async ( command: string, - options?: { cwd?: string; env?: object } + options?: { cwd?: string; env?: object; logLevel?: LogLevel } ) => { - const { cwd = ".", env = {} } = options || {}; + const { cwd = ".", env = {}, logLevel = "info" as LogLevel } = options || {}; try { if (!existsSync(cwd)) { @@ -29,7 +31,8 @@ export const runShellCommandWithLogger = async ( const readStream = async ( reader: typeof stdoutReader | typeof stderrReader, - streamName: string + streamName: string, + logLevel: LogLevel ) => { try { while (true) { @@ -37,7 +40,9 @@ export const runShellCommandWithLogger = async ( if (done) break; const text = new TextDecoder().decode(value); const trimmedText = text.trim(); - logger.info(trimmedText.includes("\n") ? `\n${trimmedText}` : trimmedText); + if (trimmedText) { + logger[logLevel](trimmedText.includes("\n") ? `\n${trimmedText}` : trimmedText); + } } } catch (err) { logger.error(`Error reading from ${streamName} stream:`, err); @@ -46,7 +51,10 @@ export const runShellCommandWithLogger = async ( } }; - Promise.all([readStream(stdoutReader, "stdout"), readStream(stderrReader, "stderr")]); + Promise.all([ + readStream(stdoutReader, "stdout", logLevel), + readStream(stderrReader, "stderr", "error") + ]); await proc.exited; } catch (err) {