fix(sdk): silence provider logs in deriveIsmConfig (#4194)

### Description

- silences provider logs in deriveIsmConfig, like deriveHookConfig
- created HyperlaneReader class for readers to extend in order to reuse
`setSmartProviderLogLevel`

### Drive-by changes

- none

### Related issues

- fixes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/4061

### Backward compatibility

- yes

### Testing

- manual
- ci
dan/relayer-images-bump
Noah Bayindirli 🥂 4 months ago committed by GitHub
parent 5c93f69238
commit ed63e04c4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/lazy-years-judge.md
  2. 28
      typescript/sdk/src/hook/EvmHookReader.ts
  3. 79
      typescript/sdk/src/ism/EvmIsmReader.ts
  4. 2
      typescript/sdk/src/providers/SmartProvider/SmartProvider.ts
  5. 19
      typescript/sdk/src/token/EvmERC20WarpRouteReader.ts
  6. 28
      typescript/sdk/src/utils/HyperlaneReader.ts

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': patch
---
Creates HyperlaneReader to re-use dyn provider log level & silences provider logs in deriveIsmConfig like deriveHookConfig.

@ -1,4 +1,4 @@
import { ethers, providers } from 'ethers';
import { ethers } from 'ethers';
import {
DomainRoutingHook,
@ -27,6 +27,7 @@ import {
import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/concurrency.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainNameOrId } from '../types.js';
import { HyperlaneReader } from '../utils/HyperlaneReader.js';
import {
AggregationHookConfig,
@ -75,8 +76,7 @@ export interface HookReader {
): void;
}
export class EvmHookReader implements HookReader {
protected readonly provider: providers.Provider;
export class EvmHookReader extends HyperlaneReader implements HookReader {
protected readonly logger = rootLogger.child({ module: 'EvmHookReader' });
constructor(
@ -86,15 +86,15 @@ export class EvmHookReader implements HookReader {
chain,
) ?? DEFAULT_CONTRACT_READ_CONCURRENCY,
) {
this.provider = multiProvider.getProvider(chain);
super(multiProvider, chain);
}
async deriveHookConfig(address: Address): Promise<DerivedHookConfig> {
let onchainHookType = undefined;
let onchainHookType: OnchainHookType | undefined = undefined;
let derivedHookConfig: DerivedHookConfig;
try {
const hook = IPostDispatchHook__factory.connect(address, this.provider);
this.logger.debug('Deriving HookConfig', { address });
this.logger.debug('Deriving HookConfig:', { address });
// Temporarily turn off SmartProvider logging
// Provider errors are expected because deriving will call methods that may not exist in the Bytecode
@ -147,10 +147,10 @@ export class EvmHookReader implements HookReader {
this.logger.debug(`${customMessage}:\n\t${e}`);
}
throw new Error(`${customMessage}:\n\t${e}`);
} finally {
this.setSmartProviderLogLevel(getLogLevel()); // returns to original level defined by rootLogger
}
this.setSmartProviderLogLevel(getLogLevel()); // returns to original level defined by rootLogger
return derivedHookConfig;
}
@ -389,18 +389,6 @@ export class EvmHookReader implements HookReader {
};
}
/**
* Conditionally sets the log level for a smart provider.
*
* @param level - The log level to set, e.g. 'debug', 'info', 'warn', 'error'.
*/
protected setSmartProviderLogLevel(level: string): void {
if ('setLogLevel' in this.provider) {
//@ts-ignore
this.provider.setLogLevel(level);
}
}
assertHookType(
hookType: OnchainHookType,
expectedType: OnchainHookType,

@ -1,4 +1,4 @@
import { ethers, providers } from 'ethers';
import { ethers } from 'ethers';
import {
DefaultFallbackRoutingIsm__factory,
@ -14,12 +14,14 @@ import {
WithAddress,
assert,
concurrentMap,
getLogLevel,
rootLogger,
} from '@hyperlane-xyz/utils';
import { DEFAULT_CONTRACT_READ_CONCURRENCY } from '../consts/concurrency.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainNameOrId } from '../types.js';
import { HyperlaneReader } from '../utils/HyperlaneReader.js';
import {
AggregationIsmConfig,
@ -49,8 +51,7 @@ export interface IsmReader {
): void;
}
export class EvmIsmReader implements IsmReader {
protected readonly provider: providers.Provider;
export class EvmIsmReader extends HyperlaneReader implements IsmReader {
protected readonly logger = rootLogger.child({ module: 'EvmIsmReader' });
constructor(
@ -60,37 +61,57 @@ export class EvmIsmReader implements IsmReader {
chain,
) ?? DEFAULT_CONTRACT_READ_CONCURRENCY,
) {
this.provider = multiProvider.getProvider(chain);
super(multiProvider, chain);
}
async deriveIsmConfig(address: Address): Promise<DerivedIsmConfig> {
const ism = IInterchainSecurityModule__factory.connect(
address,
this.provider,
);
const moduleType: ModuleType = await ism.moduleType();
this.logger.debug('Deriving ISM config', { address, moduleType });
let moduleType: ModuleType | undefined = undefined;
let derivedIsmConfig: DerivedIsmConfig;
try {
const ism = IInterchainSecurityModule__factory.connect(
address,
this.provider,
);
this.logger.debug('Deriving IsmConfig:', { address });
// Temporarily turn off SmartProvider logging
// Provider errors are expected because deriving will call methods that may not exist in the Bytecode
this.setSmartProviderLogLevel('silent');
moduleType = await ism.moduleType();
switch (moduleType) {
case ModuleType.UNUSED:
throw new Error('UNUSED does not have a corresponding IsmType');
case ModuleType.ROUTING:
// IsmType is either ROUTING or FALLBACK_ROUTING, but that's determined inside deriveRoutingConfig
return this.deriveRoutingConfig(address);
case ModuleType.AGGREGATION:
return this.deriveAggregationConfig(address);
case ModuleType.LEGACY_MULTISIG:
throw new Error('LEGACY_MULTISIG is deprecated and not supported');
case ModuleType.MERKLE_ROOT_MULTISIG:
case ModuleType.MESSAGE_ID_MULTISIG:
return this.deriveMultisigConfig(address);
case ModuleType.NULL:
return this.deriveNullConfig(address);
case ModuleType.CCIP_READ:
throw new Error('CCIP_READ does not have a corresponding IsmType');
default:
throw new Error('Unknown ModuleType');
switch (moduleType) {
case ModuleType.UNUSED:
throw new Error('UNUSED does not have a corresponding IsmType');
case ModuleType.ROUTING:
// IsmType is either ROUTING or FALLBACK_ROUTING, but that's determined inside deriveRoutingConfig
derivedIsmConfig = await this.deriveRoutingConfig(address);
break;
case ModuleType.AGGREGATION:
derivedIsmConfig = await this.deriveAggregationConfig(address);
break;
case ModuleType.LEGACY_MULTISIG:
throw new Error('LEGACY_MULTISIG is deprecated and not supported');
case ModuleType.MERKLE_ROOT_MULTISIG:
case ModuleType.MESSAGE_ID_MULTISIG:
derivedIsmConfig = await this.deriveMultisigConfig(address);
break;
case ModuleType.NULL:
derivedIsmConfig = await this.deriveNullConfig(address);
break;
case ModuleType.CCIP_READ:
throw new Error('CCIP_READ does not have a corresponding IsmType');
default:
throw new Error(`Unknown ISM ModuleType: ${moduleType}`);
}
} catch (e: any) {
const errorMessage = `Failed to derive ISM module type ${moduleType} (${address}):\n\t${e}`;
this.logger.debug(errorMessage);
throw new Error(errorMessage);
} finally {
this.setSmartProviderLogLevel(getLogLevel()); // returns to original level defined by rootLogger
}
return derivedIsmConfig;
}
async deriveRoutingConfig(

@ -97,7 +97,7 @@ export class HyperlaneSmartProvider
this.supportedMethods = [...supportedMethods.values()];
}
setLogLevel(level: pino.LevelWithSilentOrString) {
setLogLevel(level: pino.LevelWithSilentOrString): void {
this.logger.level = level;
}

@ -1,4 +1,4 @@
import { BigNumber, constants, providers } from 'ethers';
import { BigNumber, constants } from 'ethers';
import {
HypERC20CollateralVaultDeposit__factory,
@ -25,15 +25,15 @@ import { EvmIsmReader } from '../ism/EvmIsmReader.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { RemoteRouters } from '../router/types.js';
import { ChainNameOrId } from '../types.js';
import { HyperlaneReader } from '../utils/HyperlaneReader.js';
import { CollateralExtensions } from './config.js';
import { TokenMetadata } from './types.js';
export class EvmERC20WarpRouteReader {
export class EvmERC20WarpRouteReader extends HyperlaneReader {
protected readonly logger = rootLogger.child({
module: 'EvmERC20WarpRouteReader',
});
provider: providers.Provider;
evmHookReader: EvmHookReader;
evmIsmReader: EvmIsmReader;
@ -42,7 +42,7 @@ export class EvmERC20WarpRouteReader {
protected readonly chain: ChainNameOrId,
protected readonly concurrency: number = DEFAULT_CONTRACT_READ_CONCURRENCY,
) {
this.provider = this.multiProvider.getProvider(chain);
super(multiProvider, chain);
this.evmHookReader = new EvmHookReader(multiProvider, chain, concurrency);
this.evmIsmReader = new EvmIsmReader(multiProvider, chain, concurrency);
}
@ -234,15 +234,4 @@ export class EvmERC20WarpRouteReader {
),
);
}
/**
* Conditionally sets the log level for a smart provider.
*
* @param level - The log level to set, e.g. 'debug', 'info', 'warn', 'error'.
*/
protected setSmartProviderLogLevel(level: string) {
if ('setLogLevel' in this.provider) {
//@ts-ignore
this.provider.setLogLevel(level);
}
}
}

@ -0,0 +1,28 @@
import { providers } from 'ethers';
import { LevelWithSilentOrString } from 'pino';
import { MultiProvider } from '../providers/MultiProvider.js';
import { HyperlaneSmartProvider } from '../providers/SmartProvider/SmartProvider.js';
import { ChainNameOrId } from '../types.js';
export class HyperlaneReader {
provider: providers.Provider;
constructor(
protected readonly multiProvider: MultiProvider,
protected readonly chain: ChainNameOrId,
) {
this.provider = this.multiProvider.getProvider(chain);
}
/**
* Conditionally sets the log level for a smart provider.
*
* @param level - The log level to set, e.g. 'debug', 'info', 'warn', 'error'.
*/
protected setSmartProviderLogLevel(level: LevelWithSilentOrString): void {
if ('setLogLevel' in this.provider) {
(this.provider as HyperlaneSmartProvider).setLogLevel(level);
}
}
}
Loading…
Cancel
Save