Skip to content

Commit

Permalink
feat: do not exhaustively derive routing config in TS relayer (#4765)
Browse files Browse the repository at this point in the history
### Description

CLI commands using HyperlaneRelayer (`--relay`) were very slow due to
exhaustive routing ISM/hook derivation. This short-circuits the
derivation when there is a known "message context" to evaluate the
routing hook and ISMs for.

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility

Yes

### Testing

Manual
  • Loading branch information
yorhodes authored and paulbalaji committed Oct 29, 2024
1 parent ba193fc commit 081e709
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/cold-dingos-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': patch
---

Optimize HyperlaneRelayer routing config derivation
20 changes: 16 additions & 4 deletions typescript/sdk/src/core/HyperlaneRelayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,18 @@ export class HyperlaneRelayer {
async getHookConfig(
chain: ChainName,
hook: Address,
messageContext?: DispatchedMessage,
): Promise<DerivedHookConfig> {
let config: DerivedHookConfig | undefined;
if (this.cache?.hook[chain]?.[hook]) {
config = this.cache.hook[chain][hook] as DerivedHookConfig | undefined;
} else {
const evmHookReader = new EvmHookReader(this.multiProvider, chain);
const evmHookReader = new EvmHookReader(
this.multiProvider,
chain,
undefined,
messageContext,
);
config = await evmHookReader.deriveHookConfig(hook);
}

Expand All @@ -98,12 +104,18 @@ export class HyperlaneRelayer {
async getIsmConfig(
chain: ChainName,
ism: Address,
messageContext?: DispatchedMessage,
): Promise<DerivedIsmConfig> {
let config: DerivedIsmConfig | undefined;
if (this.cache?.ism[chain]?.[ism]) {
config = this.cache.ism[chain][ism] as DerivedIsmConfig | undefined;
} else {
const evmIsmReader = new EvmIsmReader(this.multiProvider, chain);
const evmIsmReader = new EvmIsmReader(
this.multiProvider,
chain,
undefined,
messageContext,
);
config = await evmIsmReader.deriveIsmConfig(ism);
}

Expand All @@ -124,15 +136,15 @@ export class HyperlaneRelayer {
): Promise<DerivedHookConfig> {
const originChain = this.core.getOrigin(message);
const hook = await this.core.getSenderHookAddress(message);
return this.getHookConfig(originChain, hook);
return this.getHookConfig(originChain, hook, message);
}

async getRecipientIsmConfig(
message: DispatchedMessage,
): Promise<DerivedIsmConfig> {
const destinationChain = this.core.getDestination(message);
const ism = await this.core.getRecipientIsmAddress(message);
return this.getIsmConfig(destinationChain, ism);
return this.getIsmConfig(destinationChain, ism, message);
}

async relayMessage(
Expand Down
8 changes: 7 additions & 1 deletion typescript/sdk/src/hook/EvmHookReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '@hyperlane-xyz/utils';

import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/concurrency.js';
import { DispatchedMessage } from '../core/types.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainNameOrId } from '../types.js';
import { HyperlaneReader } from '../utils/HyperlaneReader.js';
Expand Down Expand Up @@ -96,6 +97,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader {
protected readonly concurrency: number = multiProvider.tryGetRpcConcurrency(
chain,
) ?? DEFAULT_CONTRACT_READ_CONCURRENCY,
protected readonly messageContext?: DispatchedMessage,
) {
super(multiProvider, chain);
}
Expand Down Expand Up @@ -379,6 +381,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader {
address: Address,
): Promise<WithAddress<DomainRoutingHookConfig>> {
const hook = DomainRoutingHook__factory.connect(address, this.provider);

this.assertHookType(await hook.hookType(), OnchainHookType.ROUTING);

const owner = await hook.owner();
Expand All @@ -403,6 +406,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader {
address,
this.provider,
);

this.assertHookType(
await hook.hookType(),
OnchainHookType.FALLBACK_ROUTING,
Expand Down Expand Up @@ -430,7 +434,9 @@ export class EvmHookReader extends HyperlaneReader implements HookReader {
private async fetchDomainHooks(
hook: DomainRoutingHook | FallbackDomainRoutingHook,
): Promise<RoutingHookConfig['domains']> {
const domainIds = this.multiProvider.getKnownDomainIds();
const domainIds = this.messageContext
? [this.messageContext.parsed.destination]
: this.multiProvider.getKnownDomainIds();

const domainHooks: RoutingHookConfig['domains'] = {};
await concurrentMap(this.concurrency, domainIds, async (domainId) => {
Expand Down
9 changes: 7 additions & 2 deletions typescript/sdk/src/ism/EvmIsmReader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ethers } from 'ethers';
import { BigNumber, ethers } from 'ethers';

import {
ArbL2ToL1Ism__factory,
Expand All @@ -21,6 +21,7 @@ import {
} from '@hyperlane-xyz/utils';

import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/concurrency.js';
import { DispatchedMessage } from '../core/types.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainNameOrId } from '../types.js';
import { HyperlaneReader } from '../utils/HyperlaneReader.js';
Expand Down Expand Up @@ -66,6 +67,7 @@ export class EvmIsmReader extends HyperlaneReader implements IsmReader {
protected readonly concurrency: number = multiProvider.tryGetRpcConcurrency(
chain,
) ?? DEFAULT_CONTRACT_READ_CONCURRENCY,
protected readonly messageContext?: DispatchedMessage,
) {
super(multiProvider, chain);
}
Expand Down Expand Up @@ -129,11 +131,14 @@ export class EvmIsmReader extends HyperlaneReader implements IsmReader {
address,
this.provider,
);

const owner = await ism.owner();
this.assertModuleType(await ism.moduleType(), ModuleType.ROUTING);

const domainIds = this.messageContext
? [BigNumber.from(this.messageContext.parsed.origin)]
: await ism.domains();
const domains: RoutingIsmConfig['domains'] = {};
const domainIds = await ism.domains();

await concurrentMap(this.concurrency, domainIds, async (domainId) => {
const chainName = this.multiProvider.tryGetChainName(domainId.toNumber());
Expand Down

0 comments on commit 081e709

Please sign in to comment.