diff --git a/npm/CHANGELOG.md b/npm/CHANGELOG.md index 5fc0266..75b576f 100644 --- a/npm/CHANGELOG.md +++ b/npm/CHANGELOG.md @@ -4,7 +4,7 @@ ### Minor Changes -- c9bf54c: Update to latest cosmos registry +- c9bf54c: Updating testnet chain id fallback logic ## 11.1.0 diff --git a/npm/src/bundled.test.ts b/npm/src/bundled.test.ts index 396e44d..6c82342 100644 --- a/npm/src/bundled.test.ts +++ b/npm/src/bundled.test.ts @@ -17,10 +17,20 @@ describe('BundledClient', () => { expect(() => bundled.get('unknown')).toThrow('Registry not found for unknown'); }); - it.skip('handles preview chain IDs by swapping them', () => { - const registry = bundled.get('penumbra-testnet-deimos-8-xf2dbce94'); + it('returns a random suffix chain ID if available', () => { + const registry = bundled.get('penumbra-testnet-deimos-8-x6de97e39'); expect(registry).toBeInstanceOf(Registry); - expect(registry.chainId).toEqual('penumbra-testnet-deimos-8'); + expect(registry.chainId).toEqual('penumbra-testnet-deimos-8-x6de97e39'); + }); + + it('swaps a random suffix chain ID by swapping them if it is not present', () => { + const registry = bundled.get('penumbra-testnet-phobos-1-xf2dbce94'); + expect(registry).toBeInstanceOf(Registry); + expect(registry.chainId).toEqual('penumbra-testnet-phobos-1'); + }); + + it('fails if swapped random suffix chain ID is not present', () => { + expect(() => bundled.get('penumbra-testnet-jupiter-1-xf2dbce94')).toThrow(); }); it('returns staking asset global as expected', () => { diff --git a/npm/src/bundled.ts b/npm/src/bundled.ts index fe524df..623488f 100644 --- a/npm/src/bundled.ts +++ b/npm/src/bundled.ts @@ -1,17 +1,26 @@ import { Registry } from './registry'; import { allJsonRegistries } from './json'; -import { swapIfPreviewChain } from './preview'; import * as GlobalsJson from '../../registry/globals.json'; import { RegistryGlobals } from './globals'; +import { deriveTestnetChainIdFromPreview, isTestnetPreviewChainId } from './utils/testnet-parser'; export class BundledClient { get(chainId: string): Registry { - const chainIdToIndex = swapIfPreviewChain(chainId); - const jsonRegistry = allJsonRegistries[chainIdToIndex]; - if (!jsonRegistry) { - throw new Error(`Registry not found for ${chainIdToIndex}`); + const jsonRegistry = allJsonRegistries[chainId]; + if (jsonRegistry) { + return new Registry(jsonRegistry); } - return new Registry(jsonRegistry); + + if (isTestnetPreviewChainId(chainId)) { + const fallbackChainId = deriveTestnetChainIdFromPreview(chainId); + console.warn(`Attempting to get fallback chain registry: ${fallbackChainId}`); + const fallbackRegistry = allJsonRegistries[fallbackChainId]; + if (fallbackRegistry) { + return new Registry(fallbackRegistry); + } + } + + throw new Error(`Registry not found for ${chainId}`); } globals(): RegistryGlobals { diff --git a/npm/src/json.ts b/npm/src/json.ts index 9884c34..e2c595f 100644 --- a/npm/src/json.ts +++ b/npm/src/json.ts @@ -49,7 +49,7 @@ interface Image { } export const allJsonRegistries: Record = { - 'penumbra-testnet-deimos-8': Deimos8, + 'penumbra-testnet-deimos-8-x6de97e39': Deimos8, 'penumbra-1': Penumbra1, 'penumbra-testnet-phobos-1': Phobos1, }; diff --git a/npm/src/registry.test.ts b/npm/src/registry.test.ts index bdfd2f8..c86af82 100644 --- a/npm/src/registry.test.ts +++ b/npm/src/registry.test.ts @@ -19,15 +19,14 @@ describe('Registry', () => { expect(getCubeMetadata).toThrow(); }); - it.skip('gets all assets successfully', () => { + it('gets all assets successfully', () => { const registry = new Registry(testRegistry); const res = registry.getAllAssets(); - expect(res.length).toEqual(20); + expect(res.length).toBeGreaterThan(0); }); - it.skip('versions correctly', async () => { + it('versions without throwing', async () => { const registry = new Registry(testRegistry); - const version = await registry.version(); - expect(version).toEqual('9eaf48c7cbf3248e6979830cfc982f2208eeec0fcc4c0e2802f0bd43c8bffad3'); + await expect(registry.version()).resolves.not.toThrow(); }); }); diff --git a/npm/src/remote.test.ts b/npm/src/remote.test.ts index 5b97864..c6a5012 100644 --- a/npm/src/remote.test.ts +++ b/npm/src/remote.test.ts @@ -3,7 +3,7 @@ import fetchMock from 'fetch-mock'; import { RemoteClient } from './remote'; import { REGISTRY_BASE_URL } from './github'; import { ChainRegistryClient } from './client'; -import * as Deimos8 from '../../registry/chains/penumbra-testnet-deimos-8-x6de97e39.json'; +import * as Phobos1 from '../../registry/chains/penumbra-testnet-phobos-1.json'; import * as GlobalsJson from '../../registry/globals.json'; describe('RemoteClient', () => { @@ -24,15 +24,15 @@ describe('RemoteClient', () => { const endpoint = `${REGISTRY_BASE_URL}/chains/${chainId}.json`; fetchMock.mock(endpoint, { status: 200, - body: Deimos8, + body: Phobos1, }); const registry = await rClient.get(chainId); expect(fetchMock.called(endpoint)).toBe(true); - expect(registry.chainId).toEqual(Deimos8.chainId); - expect(registry.ibcConnections).toEqual(Deimos8.ibcConnections); - expect(registry.getAllAssets().length).toEqual(Object.keys(Deimos8.assetById).length); + expect(registry.chainId).toEqual(Phobos1.chainId); + expect(registry.ibcConnections).toEqual(Phobos1.ibcConnections); + expect(registry.getAllAssets().length).toEqual(Object.keys(Phobos1.assetById).length); }); it('should throw if there is not a remote version', async () => { @@ -59,25 +59,69 @@ describe('RemoteClient', () => { expect(registry.rpcs).toEqual(GlobalsJson.rpcs); }); + describe('testnet preview', () => { + it('fetches falls back if available', async () => { + const testnetPreviewChainId = 'penumbra-testnet-phobos-1-x6de97e39'; + const firstCall = `${REGISTRY_BASE_URL}/chains/${testnetPreviewChainId}.json`; + fetchMock.mock(firstCall, { + status: 404, + }); + const fallbackChainId = 'penumbra-testnet-phobos-1'; + const secondCall = `${REGISTRY_BASE_URL}/chains/${fallbackChainId}.json`; + fetchMock.mock(secondCall, { + status: 200, + body: Phobos1, + }); + + const registry = await rClient.get(testnetPreviewChainId); + + expect(fetchMock.called(firstCall)).toBe(true); + expect(fetchMock.called(secondCall)).toBe(true); + expect(registry.chainId).toEqual(Phobos1.chainId); + expect(registry.ibcConnections).toEqual(Phobos1.ibcConnections); + expect(registry.getAllAssets().length).toEqual(Object.keys(Phobos1.assetById).length); + }); + + it('throws if falls back not available', async () => { + const testnetPreviewChainId = 'penumbra-testnet-phobos-1-x6de97e39'; + const firstCall = `${REGISTRY_BASE_URL}/chains/${testnetPreviewChainId}.json`; + fetchMock.mock(firstCall, { + status: 404, + }); + const fallbackChainId = 'penumbra-testnet-phobos-1'; + const secondCall = `${REGISTRY_BASE_URL}/chains/${fallbackChainId}.json`; + fetchMock.mock(secondCall, { + status: 404, + }); + + await expect(rClient.get(testnetPreviewChainId)).rejects.toThrow( + `Failed to fetch from: ${secondCall}`, + ); + + expect(fetchMock.called(firstCall)).toBe(true); + expect(fetchMock.called(secondCall)).toBe(true); + }); + }); + describe('getWithBundledBackup', () => { it('fetches remote when available', async () => { const chainId = 'test-chain-7'; const endpoint = `${REGISTRY_BASE_URL}/chains/${chainId}.json`; fetchMock.mock(endpoint, { status: 200, - body: Deimos8, + body: Phobos1, }); const registry = await rClient.getWithBundledBackup(chainId); expect(fetchMock.called(endpoint)).toBe(true); - expect(registry.chainId).toEqual(Deimos8.chainId); - expect(registry.ibcConnections).toEqual(Deimos8.ibcConnections); - expect(registry.getAllAssets().length).toEqual(Object.keys(Deimos8.assetById).length); + expect(registry.chainId).toEqual(Phobos1.chainId); + expect(registry.ibcConnections).toEqual(Phobos1.ibcConnections); + expect(registry.getAllAssets().length).toEqual(Object.keys(Phobos1.assetById).length); }); it('fetches bundled when available', async () => { - const chainId = 'penumbra-testnet-deimos-8'; + const chainId = 'penumbra-testnet-phobos-1'; const endpoint = `${REGISTRY_BASE_URL}/chains/${chainId}.json`; fetchMock.mock(endpoint, { status: 404, @@ -86,9 +130,9 @@ describe('RemoteClient', () => { const registry = await rClient.getWithBundledBackup(chainId); expect(fetchMock.called(endpoint)).toBe(true); - expect(registry.chainId).toEqual(Deimos8.chainId); - expect(registry.ibcConnections).toEqual(Deimos8.ibcConnections); - expect(registry.getAllAssets().length).toEqual(Object.keys(Deimos8.assetById).length); + expect(registry.chainId).toEqual(Phobos1.chainId); + expect(registry.ibcConnections).toEqual(Phobos1.ibcConnections); + expect(registry.getAllAssets().length).toEqual(Object.keys(Phobos1.assetById).length); }); }); }); diff --git a/npm/src/remote.ts b/npm/src/remote.ts index 1b24c51..7c4398c 100644 --- a/npm/src/remote.ts +++ b/npm/src/remote.ts @@ -1,8 +1,8 @@ import { Registry } from './registry'; import { GithubFetcher } from './github'; -import { swapIfPreviewChain } from './preview'; import { RegistryGlobals } from './globals'; import { BundledClient } from './bundled'; +import { deriveTestnetChainIdFromPreview, isTestnetPreviewChainId } from './utils/testnet-parser'; export class RemoteClient { private readonly github = new GithubFetcher(); @@ -10,8 +10,16 @@ export class RemoteClient { constructor(private readonly bundled: BundledClient) {} async get(chainId: string): Promise { - const chainIdToQuery = swapIfPreviewChain(chainId); - return this.github.fetchRegistry(chainIdToQuery); + try { + return await this.github.fetchRegistry(chainId); + } catch (e) { + if (isTestnetPreviewChainId(chainId)) { + const fallbackChainId = deriveTestnetChainIdFromPreview(chainId); + console.warn(`Attempting to fetch fallback chain registry: ${fallbackChainId}`); + return await this.github.fetchRegistry(fallbackChainId); + } + throw e; + } } // If remote fails, fall back to bundled registry for chain diff --git a/npm/src/utils/testnet-parser.test.ts b/npm/src/utils/testnet-parser.test.ts index 62bb972..6eca006 100644 --- a/npm/src/utils/testnet-parser.test.ts +++ b/npm/src/utils/testnet-parser.test.ts @@ -37,5 +37,6 @@ describe('testnet-preview helper', () => { expect(deriveTestnetChainIdFromPreview('penumbra-testnet-tethys12-b4d8f9a0')).toEqual( 'penumbra-testnet-tethys12', ); + expect(deriveTestnetChainIdFromPreview('penumbra-testnet-deimos-8')).toEqual(''); }); });