From d93a38cabcfd8fae7deb0af82b40b8edde9e34fd Mon Sep 17 00:00:00 2001 From: Mohammed Hussan Date: Sun, 9 Feb 2025 16:25:13 +0000 Subject: [PATCH] fix(checker): Add MissingRouterViolation when config misses enrolled routers (#5391) ### Description - In response to an error thrown when there are actual enrolled routers that are not present in the config, this was encountered running the warp checker against a route not managed by AW. Here is the violation output ![image](https://github.com/user-attachments/assets/67d6b428-c669-4e27-9278-bf3404129473) ### Testing Manual --- .changeset/wicked-bags-enjoy.md | 5 +++ .../infra/src/govern/HyperlaneICAChecker.ts | 2 +- .../infra/src/govern/ProxiedRouterGovernor.ts | 2 +- .../sdk/src/router/HyperlaneRouterChecker.ts | 43 +++++++++++++++---- typescript/sdk/src/router/types.ts | 11 ++++- 5 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 .changeset/wicked-bags-enjoy.md diff --git a/.changeset/wicked-bags-enjoy.md b/.changeset/wicked-bags-enjoy.md new file mode 100644 index 0000000000..51341c3fa7 --- /dev/null +++ b/.changeset/wicked-bags-enjoy.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/sdk': minor +--- + +Add MissingRouterViolation when config misses enrolled routers diff --git a/typescript/infra/src/govern/HyperlaneICAChecker.ts b/typescript/infra/src/govern/HyperlaneICAChecker.ts index cb72bd73a6..940b43a61b 100644 --- a/typescript/infra/src/govern/HyperlaneICAChecker.ts +++ b/typescript/infra/src/govern/HyperlaneICAChecker.ts @@ -43,7 +43,7 @@ export class HyperlaneICAChecker extends InterchainAccountChecker { const violation: RouterViolation = { chain, - type: RouterViolationType.EnrolledRouter, + type: RouterViolationType.MisconfiguredEnrolledRouter, contract: router, actual: currentRouters, expected: expectedRouters, diff --git a/typescript/infra/src/govern/ProxiedRouterGovernor.ts b/typescript/infra/src/govern/ProxiedRouterGovernor.ts index d07c55395c..62d66bc68a 100644 --- a/typescript/infra/src/govern/ProxiedRouterGovernor.ts +++ b/typescript/infra/src/govern/ProxiedRouterGovernor.ts @@ -24,7 +24,7 @@ export class ProxiedRouterGovernor< switch (violation.type) { case ConnectionClientViolationType.InterchainSecurityModule: return this.handleIsmViolation(violation as ConnectionClientViolation); - case RouterViolationType.EnrolledRouter: + case RouterViolationType.MisconfiguredEnrolledRouter: return this.handleEnrolledRouterViolation(violation as RouterViolation); case ViolationType.Owner: return this.handleOwnerViolation(violation as OwnerViolation); diff --git a/typescript/sdk/src/router/HyperlaneRouterChecker.ts b/typescript/sdk/src/router/HyperlaneRouterChecker.ts index 7a8c5e3f1d..a3b015fc13 100644 --- a/typescript/sdk/src/router/HyperlaneRouterChecker.ts +++ b/typescript/sdk/src/router/HyperlaneRouterChecker.ts @@ -20,6 +20,7 @@ import { RouterApp } from './RouterApps.js'; import { ClientViolation, ClientViolationType, + MissingRouterViolation, RouterConfig, RouterViolation, RouterViolationType, @@ -125,17 +126,27 @@ export class HyperlaneRouterChecker< async checkEnrolledRouters(chain: ChainName): Promise { const router = this.app.router(this.app.getContracts(chain)); - const remoteChains = await this.app.remoteChains(chain); + const actualRemoteChains = await this.app.remoteChains(chain); + const currentRouters: ChainMap = {}; const expectedRouters: ChainMap = {}; - const routerDiff: ChainMap<{ + + const misconfiguredRouterDiff: ChainMap<{ actual: AddressBytes32; expected: AddressBytes32; }> = {}; + const missingRouterDomains: ChainName[] = []; await Promise.all( - remoteChains.map(async (remoteChain) => { - const remoteRouterAddress = this.app.routerAddress(remoteChain); + actualRemoteChains.map(async (remoteChain) => { + let remoteRouterAddress: string; + try { + remoteRouterAddress = this.app.routerAddress(remoteChain); + } catch { + // failed to read remote router address from the config + missingRouterDomains.push(remoteChain); + return; + } const remoteDomainId = this.multiProvider.getDomainId(remoteChain); const actualRouter = await router.routers(remoteDomainId); const expectedRouter = addressToBytes32(remoteRouterAddress); @@ -144,7 +155,7 @@ export class HyperlaneRouterChecker< expectedRouters[remoteChain] = expectedRouter; if (actualRouter !== expectedRouter) { - routerDiff[remoteChain] = { + misconfiguredRouterDiff[remoteChain] = { actual: actualRouter, expected: expectedRouter, }; @@ -152,17 +163,33 @@ export class HyperlaneRouterChecker< }), ); - if (Object.keys(routerDiff).length > 0) { + const expectedRouterChains = actualRemoteChains.filter( + (chain) => !missingRouterDomains.includes(chain), + ); + + if (Object.keys(misconfiguredRouterDiff).length > 0) { const violation: RouterViolation = { chain, - type: RouterViolationType.EnrolledRouter, + type: RouterViolationType.MisconfiguredEnrolledRouter, contract: router, actual: currentRouters, expected: expectedRouters, - routerDiff, + routerDiff: misconfiguredRouterDiff, description: `Routers for some domains are missing or not enrolled correctly`, }; this.addViolation(violation); } + + if (missingRouterDomains.length > 0) { + const violation: MissingRouterViolation = { + chain, + type: RouterViolationType.MissingRouter, + contract: router, + actual: actualRemoteChains.join(','), + expected: expectedRouterChains.join(','), + description: `Routers for some domains are missing from the config`, + }; + this.addViolation(violation); + } } } diff --git a/typescript/sdk/src/router/types.ts b/typescript/sdk/src/router/types.ts index a4dd355f2f..1219498c58 100644 --- a/typescript/sdk/src/router/types.ts +++ b/typescript/sdk/src/router/types.ts @@ -48,11 +48,12 @@ export interface ClientViolation extends CheckerViolation { } export enum RouterViolationType { - EnrolledRouter = 'EnrolledRouter', + MisconfiguredEnrolledRouter = 'MisconfiguredEnrolledRouter', + MissingRouter = 'MissingRouter', } export interface RouterViolation extends CheckerViolation { - type: RouterViolationType.EnrolledRouter; + type: RouterViolationType.MisconfiguredEnrolledRouter; contract: Router; routerDiff: ChainMap<{ actual: AddressBytes32; @@ -61,6 +62,12 @@ export interface RouterViolation extends CheckerViolation { description?: string; } +export interface MissingRouterViolation extends CheckerViolation { + type: RouterViolationType.MissingRouter; + contract: Router; + description?: string; +} + export type RemoteRouters = z.infer; export type DestinationGas = z.infer;