Skip to content

Commit 915ad89

Browse files
committed
start by adding some relayers
1 parent 6a3fe8c commit 915ad89

File tree

4 files changed

+1297
-1
lines changed

4 files changed

+1297
-1
lines changed

packages/packages/generator/__tests__/builder.test.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,96 @@ describe('BuilderManager Tests', () => {
307307
.sort();
308308
expect(directories).toEqual(['explorer', 'registry']);
309309
});
310+
311+
it('should handle relayer configuration', () => {
312+
const relayerConfig = {
313+
name: 'relayer-testnet',
314+
chains: [
315+
{
316+
id: 'osmosis-1',
317+
name: 'osmosis' as const,
318+
numValidators: 1,
319+
prefix: 'osmo',
320+
denom: 'uosmo'
321+
},
322+
{
323+
id: 'cosmoshub-4',
324+
name: 'cosmoshub' as const,
325+
numValidators: 1,
326+
prefix: 'cosmos',
327+
denom: 'uatom'
328+
}
329+
],
330+
relayers: [
331+
{
332+
name: 'hermes-relay',
333+
type: 'hermes' as const,
334+
replicas: 1,
335+
chains: ['osmosis-1', 'cosmoshub-4'],
336+
config: {
337+
global: { log_level: 'info' },
338+
mode: {
339+
clients: { enabled: true, refresh: true, misbehaviour: true },
340+
connections: { enabled: true },
341+
channels: { enabled: true },
342+
packets: { enabled: true, clear_interval: 100, clear_on_start: true, tx_confirmation: true }
343+
},
344+
rest: { enabled: true, host: '0.0.0.0', port: 3000 },
345+
telemetry: { enabled: true, host: '0.0.0.0', port: 3001 }
346+
}
347+
},
348+
{
349+
name: 'go-relay',
350+
type: 'go-relayer' as const,
351+
replicas: 1,
352+
chains: ['osmosis-1', 'cosmoshub-4']
353+
}
354+
]
355+
};
356+
357+
const manager = new BuilderManager(relayerConfig);
358+
359+
const testSubDir = join(testOutputDir, 'relayers');
360+
manager.build(testSubDir);
361+
362+
const yamlFiles = loadYamlFiles(testSubDir);
363+
expect(yamlFiles).toMatchSnapshot('relayers-yaml-files');
364+
365+
// Verify relayer directory exists
366+
const directories = readdirSync(testSubDir, { withFileTypes: true })
367+
.filter((item) => item.isDirectory())
368+
.map((item) => item.name)
369+
.sort();
370+
expect(directories).toContain('relayer');
371+
372+
// Verify relayer manifests are generated
373+
const relayerFiles = Object.keys(yamlFiles).filter((f) =>
374+
f.startsWith('relayer/')
375+
);
376+
expect(relayerFiles.length).toBeGreaterThan(0);
377+
378+
// Verify both relayers have their manifests
379+
const hermesManifests = Object.keys(yamlFiles).filter((f) =>
380+
f.includes('hermes-relay')
381+
);
382+
const goRelayerManifests = Object.keys(yamlFiles).filter((f) =>
383+
f.includes('go-relay')
384+
);
385+
386+
expect(hermesManifests.length).toBeGreaterThan(0);
387+
expect(goRelayerManifests.length).toBeGreaterThan(0);
388+
389+
// Verify hermes has service (go-relayer should not)
390+
const hermesServiceExists = Object.values(yamlFiles).some((content: any) =>
391+
content.kind === 'Service' && content.metadata.name.includes('hermes-relay')
392+
);
393+
const goRelayerServiceExists = Object.values(yamlFiles).some((content: any) =>
394+
content.kind === 'Service' && content.metadata.name.includes('go-relay')
395+
);
396+
397+
expect(hermesServiceExists).toBe(true);
398+
expect(goRelayerServiceExists).toBe(false);
399+
});
310400
});
311401

312402
describe('Complex Configuration Scenarios', () => {
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
import { RelayerBuilder } from '../src/builders/relayer';
2+
import { singleChainConfig } from './test-utils/config';
3+
4+
describe('RelayerBuilder', () => {
5+
it('should generate no manifests when no relayers are configured', () => {
6+
const config = { ...singleChainConfig };
7+
delete config.relayers;
8+
9+
const builder = new RelayerBuilder(config);
10+
const manifests = builder.buildManifests();
11+
12+
expect(manifests).toEqual([]);
13+
});
14+
15+
it('should generate manifests for a hermes relayer', () => {
16+
const config = {
17+
...singleChainConfig,
18+
relayers: [
19+
{
20+
name: 'osmo-cosmos',
21+
type: 'hermes' as const,
22+
replicas: 1,
23+
chains: ['osmosis-1', 'cosmoshub-4'],
24+
config: {
25+
global: { log_level: 'info' },
26+
mode: {
27+
clients: { enabled: true, refresh: true, misbehaviour: true },
28+
connections: { enabled: true },
29+
channels: { enabled: true },
30+
packets: { enabled: true, clear_interval: 100, clear_on_start: true, tx_confirmation: true }
31+
},
32+
rest: { enabled: true, host: '0.0.0.0', port: 3000 },
33+
telemetry: { enabled: true, host: '0.0.0.0', port: 3001 }
34+
}
35+
}
36+
]
37+
};
38+
39+
const builder = new RelayerBuilder(config);
40+
const manifests = builder.buildManifests();
41+
42+
expect(manifests).toHaveLength(3); // ConfigMap, Service, StatefulSet
43+
44+
const configMap = manifests.find(m => m.kind === 'ConfigMap');
45+
const service = manifests.find(m => m.kind === 'Service');
46+
const statefulSet = manifests.find(m => m.kind === 'StatefulSet');
47+
48+
expect(configMap).toBeDefined();
49+
expect(configMap.metadata.name).toBe('hermes-osmo-cosmos');
50+
expect(configMap.data['config.toml']).toContain('log_level = "info"');
51+
52+
expect(service).toBeDefined();
53+
expect(service.metadata.name).toBe('hermes-osmo-cosmos');
54+
expect(service.spec.ports).toHaveLength(2); // rest and exposer
55+
56+
expect(statefulSet).toBeDefined();
57+
expect(statefulSet.metadata.name).toBe('hermes-osmo-cosmos');
58+
expect(statefulSet.spec.replicas).toBe(1);
59+
});
60+
61+
it('should generate manifests for a go-relayer', () => {
62+
const config = {
63+
...singleChainConfig,
64+
relayers: [
65+
{
66+
name: 'go-rly',
67+
type: 'go-relayer' as const,
68+
replicas: 1,
69+
chains: ['osmosis-1', 'cosmoshub-4']
70+
}
71+
]
72+
};
73+
74+
const builder = new RelayerBuilder(config);
75+
const manifests = builder.buildManifests();
76+
77+
expect(manifests).toHaveLength(2); // ConfigMap, StatefulSet (no service)
78+
79+
const configMap = manifests.find(m => m.kind === 'ConfigMap');
80+
const statefulSet = manifests.find(m => m.kind === 'StatefulSet');
81+
82+
expect(configMap).toBeDefined();
83+
expect(configMap.metadata.name).toBe('go-relayer-go-rly');
84+
expect(configMap.data['path.json']).toContain('osmosis-1');
85+
86+
expect(statefulSet).toBeDefined();
87+
expect(statefulSet.metadata.name).toBe('go-relayer-go-rly');
88+
});
89+
90+
it('should generate manifests for a ts-relayer', () => {
91+
const config = {
92+
...singleChainConfig,
93+
relayers: [
94+
{
95+
name: 'ts-rly',
96+
type: 'ts-relayer' as const,
97+
replicas: 1,
98+
chains: ['osmosis-1', 'cosmoshub-4']
99+
}
100+
]
101+
};
102+
103+
const builder = new RelayerBuilder(config);
104+
const manifests = builder.buildManifests();
105+
106+
expect(manifests).toHaveLength(2); // ConfigMap, StatefulSet (no service)
107+
108+
const configMap = manifests.find(m => m.kind === 'ConfigMap');
109+
const statefulSet = manifests.find(m => m.kind === 'StatefulSet');
110+
111+
expect(configMap).toBeDefined();
112+
expect(configMap.metadata.name).toBe('ts-relayer-ts-rly');
113+
expect(configMap.data['template-app.yaml']).toContain('<SRC>');
114+
expect(configMap.data['registry.yaml']).toContain('osmosis-1');
115+
116+
expect(statefulSet).toBeDefined();
117+
expect(statefulSet.metadata.name).toBe('ts-relayer-ts-rly');
118+
});
119+
120+
it('should generate manifests for a neutron-query-relayer', () => {
121+
const neutronConfig = {
122+
...singleChainConfig,
123+
chains: [
124+
...singleChainConfig.chains,
125+
{
126+
id: 'neutron-1',
127+
name: 'neutron' as const,
128+
numValidators: 1,
129+
prefix: 'neutron',
130+
denom: 'untrn',
131+
home: '/root/.neutrond'
132+
}
133+
],
134+
relayers: [
135+
{
136+
name: 'neutron-query',
137+
type: 'neutron-query-relayer' as const,
138+
replicas: 1,
139+
chains: ['neutron-1', 'osmosis-1'],
140+
config: {
141+
RELAYER_NEUTRON_CHAIN_TIMEOUT: '1000s',
142+
RELAYER_NEUTRON_CHAIN_GAS_PRICES: '0.5untrn'
143+
}
144+
}
145+
]
146+
};
147+
148+
const builder = new RelayerBuilder(neutronConfig);
149+
const manifests = builder.buildManifests();
150+
151+
expect(manifests).toHaveLength(3); // ConfigMap, Service, StatefulSet
152+
153+
const configMap = manifests.find(m => m.kind === 'ConfigMap');
154+
const service = manifests.find(m => m.kind === 'Service');
155+
const statefulSet = manifests.find(m => m.kind === 'StatefulSet');
156+
157+
expect(configMap).toBeDefined();
158+
expect(configMap.metadata.name).toBe('neutron-query-relayer-neutron-query');
159+
160+
expect(service).toBeDefined();
161+
expect(service.metadata.name).toBe('neutron-query-relayer-neutron-query');
162+
163+
expect(statefulSet).toBeDefined();
164+
expect(statefulSet.metadata.name).toBe('neutron-query-relayer-neutron-query');
165+
});
166+
167+
it('should handle multiple relayers', () => {
168+
const config = {
169+
...singleChainConfig,
170+
relayers: [
171+
{
172+
name: 'hermes-rly',
173+
type: 'hermes' as const,
174+
replicas: 1,
175+
chains: ['osmosis-1', 'cosmoshub-4']
176+
},
177+
{
178+
name: 'go-rly',
179+
type: 'go-relayer' as const,
180+
replicas: 1,
181+
chains: ['osmosis-1', 'cosmoshub-4']
182+
}
183+
]
184+
};
185+
186+
const builder = new RelayerBuilder(config);
187+
const manifests = builder.buildManifests();
188+
189+
expect(manifests).toHaveLength(5); // 2 relayers: hermes (3 manifests) + go-relayer (2 manifests)
190+
191+
const hermesManifests = manifests.filter(m =>
192+
m.metadata.name.includes('hermes-rly')
193+
);
194+
const goRelayerManifests = manifests.filter(m =>
195+
m.metadata.name.includes('go-relayer-go-rly')
196+
);
197+
198+
expect(hermesManifests).toHaveLength(3);
199+
expect(goRelayerManifests).toHaveLength(2);
200+
});
201+
202+
it('should use custom image when provided', () => {
203+
const config = {
204+
...singleChainConfig,
205+
relayers: [
206+
{
207+
name: 'custom-hermes',
208+
type: 'hermes' as const,
209+
image: 'custom/hermes:latest',
210+
replicas: 1,
211+
chains: ['osmosis-1', 'cosmoshub-4']
212+
}
213+
]
214+
};
215+
216+
const builder = new RelayerBuilder(config);
217+
const manifests = builder.buildManifests();
218+
219+
const statefulSet = manifests.find(m => m.kind === 'StatefulSet');
220+
const initContainers = statefulSet.spec.template.spec.initContainers;
221+
const containers = statefulSet.spec.template.spec.containers;
222+
223+
const relayerInitContainer = initContainers.find((c: any) => c.name === 'init-relayer');
224+
const relayerContainer = containers.find((c: any) => c.name === 'relayer');
225+
226+
expect(relayerInitContainer.image).toBe('custom/hermes:latest');
227+
expect(relayerContainer.image).toBe('custom/hermes:latest');
228+
});
229+
});

packages/packages/generator/src/builders/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CosmosBuilder } from './cosmos';
88
import { ExplorerBuilder } from './explorer';
99
import { FrontendBuilder } from './frontend';
1010
import { RegistryBuilder } from './registry';
11+
import { RelayerBuilder } from './relayer';
1112

1213
export class BuilderManager {
1314
private config: StarshipConfig;
@@ -73,7 +74,8 @@ export class BuilderManager {
7374
new CosmosBuilder(this.config),
7475
new RegistryBuilder(this.config),
7576
new ExplorerBuilder(this.config),
76-
new FrontendBuilder(this.config)
77+
new FrontendBuilder(this.config),
78+
new RelayerBuilder(this.config)
7779
];
7880

7981
let allManifests: any[] = [];

0 commit comments

Comments
 (0)