Skip to content

Commit

Permalink
Merge branch 'main' into kunal/sdk-update-routing-ism
Browse files Browse the repository at this point in the history
  • Loading branch information
aroralanuk authored Dec 13, 2023
2 parents 9f92581 + b832e57 commit bb93aa1
Show file tree
Hide file tree
Showing 21 changed files with 1,143 additions and 148 deletions.
5 changes: 5 additions & 0 deletions .changeset/tiny-spiders-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---

Replace Fallback and Retry Providers with new SmartProvider with more effective fallback/retry logic
66 changes: 23 additions & 43 deletions typescript/infra/src/config/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,44 @@ import { providers } from 'ethers';

import {
ChainName,
RetryJsonRpcProvider,
RetryProviderOptions,
HyperlaneSmartProvider,
ProviderRetryOptions,
RpcConsensusType,
chainMetadata,
} from '@hyperlane-xyz/sdk';

import { getSecretRpcEndpoint } from '../agents';

import { DeployEnvironment } from './environment';

export const defaultRetry = {
maxRequests: 6,
baseRetryMs: 50,
export const defaultRetry: ProviderRetryOptions = {
maxRetries: 6,
baseRetryDelayMs: 50,
};

function buildProvider(config?: {
url?: string;
network?: providers.Networkish;
retry?: RetryProviderOptions;
}): providers.JsonRpcProvider {
return config?.retry
? new RetryJsonRpcProvider(config.retry, config?.url, config?.network)
: new providers.StaticJsonRpcProvider(config?.url, config?.network);
}

export async function fetchProvider(
environment: DeployEnvironment,
chainName: ChainName,
connectionType: RpcConsensusType = RpcConsensusType.Single,
): Promise<providers.Provider> {
const chainId = chainMetadata[chainName].chainId;
const single = connectionType === RpcConsensusType.Single;
const rpcData = await getSecretRpcEndpoint(environment, chainName, !single);
switch (connectionType) {
case RpcConsensusType.Single: {
return buildProvider({ url: rpcData[0], retry: defaultRetry });
}
case RpcConsensusType.Quorum: {
return new providers.FallbackProvider(
(rpcData as string[]).map((url) => buildProvider({ url })), // disable retry for quorum
);
}
case RpcConsensusType.Fallback: {
return new providers.FallbackProvider(
(rpcData as string[]).map((url, index) => {
const fallbackProviderConfig: providers.FallbackProviderConfig = {
provider: buildProvider({ url, retry: defaultRetry }),
// Priority is used by the FallbackProvider to determine
// how to order providers using ascending ordering.
// When not specified, all providers have the same priority
// and are ordered randomly for each RPC.
priority: index,
};
return fallbackProviderConfig;
}),
1, // a single provider is "quorum", but failure will cause failover to the next provider
);
}
default: {
throw Error(`Unsupported connectionType: ${connectionType}`);
}

if (connectionType === RpcConsensusType.Single) {
return HyperlaneSmartProvider.fromRpcUrl(chainId, rpcData[0], defaultRetry);
} else if (
connectionType === RpcConsensusType.Quorum ||
connectionType === RpcConsensusType.Fallback
) {
return new HyperlaneSmartProvider(
chainId,
rpcData.map((url) => ({ http: url })),
undefined,
// disable retry for quorum
connectionType === RpcConsensusType.Fallback ? defaultRetry : undefined,
);
} else {
throw Error(`Unsupported connectionType: ${connectionType}`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ As of now, the GCP service account that's used by the ClusterSecretStore to acce

GCP service account credentials are static and long-living, which is really unattractive. The leading alternative is workload identity, which doesn't require static and long-living credentials. For now, the GCP service account approach was used for the following reasons:

1. The existing mainnet cluster does not support workload identity. It doesn't seem like a big lift to change the cluster to support workload identity, but it was desireable to avoid a disruption by making large changes to the infrastructure.
1. The existing mainnet cluster does not support workload identity. It doesn't seem like a big lift to change the cluster to support workload identity, but it was desirable to avoid a disruption by making large changes to the infrastructure.
2. Workload identity has some less-than-attractive features, like [identity sameness](https://cloud.google.com/kubernetes-engine/docs/concepts/workload-identity), which essentially requires putting sensitive workloads in their own GCP project.

Regardless, workload identities are a more attractive long-term option, and moving to them should be relatively easy.
Expand Down
2 changes: 1 addition & 1 deletion typescript/infra/src/utils/gcloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ async function createServiceAccount(serviceAccountName: string) {

async function getServiceAccountInfo(serviceAccountName: string) {
// By filtering, we get an array with one element upon a match and an empty
// array if there is not a match, which is desireable because it never errors.
// array if there is not a match, which is desirable because it never errors.
const matches = await execCmdAndParseJson(
`gcloud iam service-accounts list --format json --filter displayName="${serviceAccountName}"`,
);
Expand Down
2 changes: 1 addition & 1 deletion typescript/infra/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function getEthereumAddress(publicKey: Buffer): string {
pubKeyBuffer = pubKeyBuffer.slice(1, pubKeyBuffer.length);

const address = ethers.utils.keccak256(pubKeyBuffer); // keccak256 hash of publicKey
const EthAddr = `0x${address.slice(-40)}`; // take last 20 bytes as ethereum adress
const EthAddr = `0x${address.slice(-40)}`; // take last 20 bytes as ethereum address
return EthAddr;
}

Expand Down
7 changes: 4 additions & 3 deletions typescript/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@
"lint": "eslint src --ext .ts",
"prepublishOnly": "yarn build",
"prettier": "prettier --write ./src",
"test": "yarn test:unit && yarn test:hardhat",
"test:unit": "mocha --config .mocharc.json './src/**/*.test.ts'",
"test": "yarn test:unit && yarn test:hardhat && yarn test:foundry",
"test:unit": "mocha --config .mocharc.json './src/**/*.test.ts' --exit",
"test:hardhat": "hardhat test $(find ./src -name \"*.hardhat-test.ts\")",
"test:metadata": "ts-node ./src/test/metadata-check.ts"
"test:metadata": "ts-node ./src/test/metadata-check.ts",
"test:foundry": "./scripts/foundry-test.sh"
},
"types": "dist/index.d.ts",
"peerDependencies": {
Expand Down
20 changes: 20 additions & 0 deletions typescript/sdk/scripts/foundry-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

function cleanup() {
set +e
pkill -f anvil
rm -rf /tmp/anvil*
set -e
}

cleanup

echo "Starting anvil chain"
anvil --chain-id 31337 -p 8545 --state /tmp/anvil1/state --gas-price 1 > /dev/null &

echo "Running mocha tests"
yarn mocha --config .mocharc.json './src/**/*.foundry-test.ts'

cleanup

echo "Done foundry tests"
24 changes: 19 additions & 5 deletions typescript/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,26 @@ export {
ViemTransaction,
ViemTransactionReceipt,
} from './providers/ProviderType';
export { HyperlaneEtherscanProvider } from './providers/SmartProvider/HyperlaneEtherscanProvider';
export { HyperlaneJsonRpcProvider } from './providers/SmartProvider/HyperlaneJsonRpcProvider';
export {
AllProviderMethods,
IProviderMethods,
ProviderMethod,
excludeProviderMethods,
} from './providers/SmartProvider/ProviderMethods';
export { HyperlaneSmartProvider } from './providers/SmartProvider/SmartProvider';
export {
ChainMetadataWithRpcConnectionInfo,
ProviderErrorResult,
ProviderPerformResult,
ProviderRetryOptions,
ProviderStatus,
ProviderSuccessResult,
ProviderTimeoutResult,
SmartProviderOptions,
} from './providers/SmartProvider/types';
export {
RetryJsonRpcProvider,
RetryProviderOptions,
} from './providers/RetryProvider';
export {
DEFAULT_RETRY_OPTIONS,
ProviderBuilderFn,
ProviderBuilderMap,
TypedProviderBuilderFn,
Expand Down
2 changes: 1 addition & 1 deletion typescript/sdk/src/ism/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export enum IsmType {
TEST_ISM = 'testIsm',
}

// mapping betweent the two enums
// mapping between the two enums
export function ismTypeToModuleType(ismType: IsmType): ModuleType {
switch (ismType) {
case IsmType.OP_STACK:
Expand Down
12 changes: 2 additions & 10 deletions typescript/sdk/src/providers/MultiProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ import { ChainMetadataManager } from '../metadata/ChainMetadataManager';
import { ChainMetadata } from '../metadata/chainMetadataTypes';
import { ChainMap, ChainName } from '../types';

import {
DEFAULT_RETRY_OPTIONS,
ProviderBuilderFn,
defaultProviderBuilder,
} from './providerBuilders';
import { ProviderBuilderFn, defaultProviderBuilder } from './providerBuilders';

type Provider = providers.Provider;

Expand Down Expand Up @@ -91,11 +87,7 @@ export class MultiProvider<MetaExt = {}> extends ChainMetadataManager<MetaExt> {
31337,
);
} else if (rpcUrls.length) {
this.providers[name] = this.providerBuilder(
rpcUrls,
chainId,
DEFAULT_RETRY_OPTIONS,
);
this.providers[name] = this.providerBuilder(rpcUrls, chainId);
} else {
return null;
}
Expand Down
42 changes: 0 additions & 42 deletions typescript/sdk/src/providers/RetryProvider.ts

This file was deleted.

Loading

0 comments on commit bb93aa1

Please sign in to comment.