Skip to content

Commit

Permalink
feat(infra): fetch registry on warp monitor startup (hyperlane-xyz#5246)
Browse files Browse the repository at this point in the history
### Description

feat: fetch registry on warp monitor startup

can describe pod to get the registry commit that a monitor was deployed
with
```
kubectl describe pod hyperlane-warp-route-brett-base-zeronetwork-0 | grep REGISTRY
      REGISTRY_COMMIT:  v6.19.1
```

### Drive-by changes

- add the entrypoint in monorepo Dockerfile to fetch registry at startup
- opens the path for removing the registry fetching from the image build
entirely, once other monorepo users (e.g. keyfunder/kathy) specify their
own registry commit to run with
- get mailbox addresses from regular registry chain addresses instead of
via warp route configs

### Related issues

resolves hyperlane-xyz#5174
resolves hyperlane-xyz#5257

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing

- spun up a BRETT/base-zeronetwork warp monitor
```sh
kubectl logs hyperlane-warp-route-brett-base-zeronetwork-0
Updating Hyperlane registry to commit: v6.19.1
From https://github.com/hyperlane-xyz/hyperlane-registry
 * tag               v6.19.1    -> FETCH_HEAD
Previous HEAD position was 80023dd feat: Add OP extension and Trumpchain warp route (hyperlane-xyz#507)
HEAD is now at e87c85f Version Packages (hyperlane-xyz#508)
bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)
{"level":30,"time":1737556333704,"pid":29,"module":"warp-balance-monitor","labels":{"chain_name":"zeronetwork","token_address":"0xf7F253769c36CC7e1B01988CFf3aE198dea2c172","token_name":"Brett","wallet_address":"0xf7F253769c36CC7e1B01988CFf3aE198dea2c172","token_standard":"EvmHypSynthetic","warp_route_id":"BRETT/base-zeronetwork","related_chain_names":"base"},"balance":1e-18,"msg":"Wallet balance updated for token"}
...
etc
```

confirmed it's validating the given commit exists
<img width="571" alt="image"
src="https://github.com/user-attachments/assets/47f7ebe8-3c64-458e-b504-43557665fd02"
/>
  • Loading branch information
paulbalaji authored Jan 23, 2025
1 parent 11cf66c commit e4c9c7d
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 39 deletions.
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@ COPY solidity ./solidity

RUN yarn build

# Baked-in registry version
# keep for back-compat until we update all usage of the monorepo image (e.g. key-funder)
ENV REGISTRY_URI="/hyperlane-registry"
ARG REGISTRY_COMMIT="main"
RUN git clone https://github.com/hyperlane-xyz/hyperlane-registry.git "$REGISTRY_URI" \
&& cd "$REGISTRY_URI" \
&& git fetch origin "$REGISTRY_COMMIT" \
&& git checkout "$REGISTRY_COMMIT"

# Add entrypoint script that allows overriding the registry commit
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
18 changes: 18 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh
set -e

# Set default registry URI, same as Dockerfile
REGISTRY_URI="/hyperlane-registry"

# Only update registry if REGISTRY_COMMIT is set
if [ -n "$REGISTRY_COMMIT" ]; then
echo "Updating Hyperlane registry to commit: ${REGISTRY_COMMIT}"
OLDPWD=$(pwd)
cd "$REGISTRY_URI"
git fetch origin "$REGISTRY_COMMIT"
git checkout "$REGISTRY_COMMIT"
cd "$OLDPWD"
fi

# Execute the main container command
exec "$@"
10 changes: 6 additions & 4 deletions typescript/infra/helm/warp-routes/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ The warp-routes container
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: IfNotPresent
env:
- name: LOG_FORMAT
value: json
command:
- name: LOG_FORMAT
value: json
- name: REGISTRY_COMMIT
value: {{ .Values.hyperlane.registryCommit }}
args:
- ./node_modules/.bin/tsx
- ./typescript/infra/scripts/warp-routes/monitor/monitor-warp-route-balances.ts
- -v
- -v
- "30000"
- --warpRouteId
- {{ .Values.warpRouteId }}
Expand Down
1 change: 1 addition & 0 deletions typescript/infra/helm/warp-routes/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ hyperlane:
runEnv: mainnet3
context: hyperlane
chains: []
registryCommit:
nameOverride: ''
fullnameOverride: ''
externalSecrets:
Expand Down
45 changes: 40 additions & 5 deletions typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { checkbox } from '@inquirer/prompts';
import { input } from '@inquirer/prompts';
import chalk from 'chalk';
import { execSync } from 'child_process';

import {
LogFormat,
LogLevel,
configureRootLogger,
rootLogger,
} from '@hyperlane-xyz/utils';

import { Contexts } from '../../config/contexts.js';
import { WarpRouteIds } from '../../config/environments/mainnet3/warp/warpIds.js';
import { getRegistry } from '../../config/registry.js';
import { HelmCommand } from '../../src/utils/helm.js';
import { WarpRouteMonitorHelmManager } from '../../src/warp/helm.js';
import {
Expand All @@ -13,7 +22,26 @@ import {
} from '../agent-utils.js';
import { getEnvironmentConfig } from '../core-utils.js';

async function validateRegistryCommit(commit: string) {
const registry = getRegistry();
const registryUri = registry.getUri();

try {
rootLogger.info(
chalk.grey.italic(`Attempting to fetch registry commit ${commit}...`),
);
execSync(`cd ${registryUri} && git fetch origin ${commit}`, {
stdio: 'inherit',
});
rootLogger.info(chalk.grey.italic('Fetch completed successfully.'));
} catch (_) {
rootLogger.error(chalk.red(`Unable to fetch registry commit ${commit}.`));
process.exit(1);
}
}

async function main() {
configureRootLogger(LogFormat.Pretty, LogLevel.Info);
const { environment, warpRouteId } = await withWarpRouteId(getArgs()).argv;

let warpRouteIds;
Expand All @@ -23,6 +51,12 @@ async function main() {
warpRouteIds = await getWarpRouteIdsInteractive();
}

const registryCommit = await input({
message:
'Enter the registry version to use (can be a commit, branch or tag):',
});
await validateRegistryCommit(registryCommit);

await assertCorrectKubeContext(getEnvironmentConfig(environment));
const agentConfig = getAgentConfig(Contexts.Hyperlane, environment);

Expand All @@ -31,6 +65,7 @@ async function main() {
warpRouteId,
environment,
agentConfig.environmentChainNames,
registryCommit,
);
await helmManager.runHelmCommand(HelmCommand.InstallOrUpgrade);
};
Expand All @@ -42,11 +77,11 @@ async function main() {
);

for (const id of warpRouteIds) {
console.log(`Deploying Warp Monitor for Warp Route ID: ${id}`);
rootLogger.info(`Deploying Warp Monitor for Warp Route ID: ${id}`);
await deployWarpMonitor(id);
}
}

main()
.then(() => console.log('Deploy successful!'))
.catch(console.error);
.then(() => rootLogger.info('Deploy successful!'))
.catch(rootLogger.error);
11 changes: 6 additions & 5 deletions typescript/infra/scripts/warp-routes/generate-warp-config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { stringify as yamlStringify } from 'yaml';

import { WarpRouteDeployConfigSchema } from '@hyperlane-xyz/sdk';
import { rootLogger } from '@hyperlane-xyz/utils';

import { getWarpConfig } from '../../config/warp.js';
import { writeYamlAtPath } from '../../src/utils/utils.js';
Expand All @@ -23,17 +24,17 @@ async function main() {
const parsed = WarpRouteDeployConfigSchema.safeParse(warpConfig);

if (!parsed.success) {
console.dir(parsed.error.format(), { depth: null });
rootLogger.error(parsed.error.format());
return;
}

console.log('Warp config:');
console.log(yamlStringify(parsed.data, null, 2));
rootLogger.info('Warp config:');
rootLogger.info(yamlStringify(parsed.data, null, 2));

if (outFile) {
console.log(`Writing config to ${outFile}`);
rootLogger.info(`Writing config to ${outFile}`);
writeYamlAtPath(outFile, parsed.data);
}
}

main().catch((err) => console.error('Error:', err));
main().catch((err) => rootLogger.error('Error:', err));
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
EvmHypXERC20LockboxAdapter,
IHypXERC20Adapter,
MultiProtocolProvider,
RouterConfig,
SealevelHypTokenAdapter,
Token,
TokenStandard,
Expand All @@ -18,10 +17,7 @@ import {
import { ProtocolType, objMap, objMerge, sleep } from '@hyperlane-xyz/utils';

import { getWarpCoreConfig } from '../../../config/registry.js';
import {
DeployEnvironment,
getRouterConfigsForAllVms,
} from '../../../src/config/environment.js';
import { DeployEnvironment } from '../../../src/config/environment.js';
import { fetchGCPSecret } from '../../../src/utils/gcloud.js';
import { startMetricsServer } from '../../../src/utils/metrics.js';
import {
Expand Down Expand Up @@ -59,16 +55,12 @@ async function main() {
const envConfig = getEnvironmentConfig(environment);
const registry = await envConfig.getRegistry();
const chainMetadata = await registry.getMetadata();
const chainAddresses = await registry.getAddresses();

// The Sealevel warp adapters require the Mailbox address, so we
// get router configs (that include the Mailbox address) for all chains
// and merge them with the chain metadata.
const routerConfig = await getRouterConfigsForAllVms(
envConfig,
await envConfig.getMultiProvider(),
);
const mailboxes = objMap(routerConfig, (_chain, config: RouterConfig) => ({
mailbox: config.mailbox,
// get mailboxes for all chains and merge them with the chain metadata.
const mailboxes = objMap(chainAddresses, (_, { mailbox }) => ({
mailbox,
}));
const multiProtocolProvider = new MultiProtocolProvider(
objMerge(chainMetadata, mailboxes),
Expand Down
2 changes: 1 addition & 1 deletion typescript/infra/scripts/warp-routes/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export async function getRouterConfig() {
).argv;
const envConfig = getEnvironmentConfig(environment);

let multiProvider = await envConfig.getMultiProvider(
const multiProvider = await envConfig.getMultiProvider(
context,
Role.Deployer,
true,
Expand Down
6 changes: 0 additions & 6 deletions typescript/infra/src/agents/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import fs from 'fs';
import { join } from 'path';

import {
Expand Down Expand Up @@ -49,11 +48,6 @@ const HELM_CHART_PATH = join(
'/../../rust/main/helm/hyperlane-agent/',
);

if (!fs.existsSync(HELM_CHART_PATH + 'Chart.yaml'))
console.warn(
`Could not find helm chart at ${HELM_CHART_PATH}; the relative path may have changed.`,
);

export abstract class AgentHelmManager extends HelmManager<HelmRootAgentValues> {
abstract readonly role: AgentRole;
readonly helmChartPath: string = HELM_CHART_PATH;
Expand Down
12 changes: 7 additions & 5 deletions typescript/infra/src/warp/helm.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { confirm } from '@inquirer/prompts';
import path from 'path';

import { difference } from '@hyperlane-xyz/utils';
import { difference, rootLogger } from '@hyperlane-xyz/utils';

import { WarpRouteIds } from '../../config/environments/mainnet3/warp/warpIds.js';
import { DeployEnvironment } from '../../src/config/environment.js';
Expand All @@ -20,6 +20,7 @@ export class WarpRouteMonitorHelmManager extends HelmManager {
readonly warpRouteId: string,
readonly runEnv: DeployEnvironment,
readonly environmentChainNames: string[],
readonly registryCommit: string,
) {
super();
}
Expand All @@ -28,13 +29,14 @@ export class WarpRouteMonitorHelmManager extends HelmManager {
return {
image: {
repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: '3738b85-20250122-164718',
tag: '49992bf-20250122-142014',
},
warpRouteId: this.warpRouteId,
fullnameOverride: this.helmReleaseName,
environment: this.runEnv,
hyperlane: {
chains: this.environmentChainNames,
registryCommit: this.registryCommit,
},
};
}
Expand Down Expand Up @@ -90,18 +92,18 @@ export class WarpRouteMonitorHelmManager extends HelmManager {
new Set(allExpectedHelmReleaseNames),
);
for (const helmRelease of unknownHelmReleases) {
console.log(
rootLogger.warn(
`Unknown Warp Monitor Helm Release: ${helmRelease} (possibly a release from a stale Warp Route ID).`,
);
const uninstall = await confirm({
message:
"Would you like to uninstall this Helm Release? Make extra sure it shouldn't exist!",
});
if (uninstall) {
console.log(`Uninstalling Helm Release: ${helmRelease}`);
rootLogger.info(`Uninstalling Helm Release: ${helmRelease}`);
await removeHelmRelease(helmRelease, namespace);
} else {
console.log(`Skipping uninstall of Helm Release: ${helmRelease}`);
rootLogger.info(`Skipping uninstall of Helm Release: ${helmRelease}`);
}
}
}
Expand Down

0 comments on commit e4c9c7d

Please sign in to comment.