The route table lives in configs/gateway/*.json, where each endpoint names both the public path and the url_pattern sent upstream. Both moved: luxd answers under /v1/chain and nothing translates between them. The operational scripts went with it — Makefiles, the roll and validator helpers, the e2e specs and the market-maker config all composed /v1/bc addresses that now reach nothing. A test that dials a dead path fails in a way that looks like the chain is down. Lines that record an observation keep their original spelling. Co-authored-by: Hanzo Dev <[email protected]>
214 lines
8.1 KiB
TypeScript
214 lines
8.1 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import {
|
|
getUrls, getChainIds, isLocal,
|
|
rpcCall, ethBlockNumber, ethChainId,
|
|
httpStatus, httpGetJson,
|
|
} from './helpers'
|
|
import { EXPLORERS } from './env'
|
|
|
|
const urls = getUrls()
|
|
const chainIds = getChainIds()
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// App Chain Health — verify each app chain C-Chain is alive and producing
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// App chain RPC endpoints (production)
|
|
const APPCHAIN_RPCS = isLocal()
|
|
? {
|
|
zoo: urls.rpcZoo,
|
|
}
|
|
: {
|
|
zoo: 'https://api.zoo.network/v1/chain/C/rpc',
|
|
hanzo: 'https://api.hanzo.network/v1/chain/C/rpc',
|
|
spc: 'https://api.spc.network/v1/chain/C/rpc',
|
|
pars: 'https://api.pars.network/v1/chain/C/rpc',
|
|
}
|
|
|
|
// ── Zoo C-Chain ────────────────────────────────────────────────────
|
|
test.describe('App Chains — Zoo', () => {
|
|
test('Zoo C-Chain RPC responds', async ({ request }) => {
|
|
let block = 0
|
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
try {
|
|
block = await ethBlockNumber(request, APPCHAIN_RPCS.zoo)
|
|
break
|
|
} catch {
|
|
if (attempt < 2) await new Promise(r => setTimeout(r, 1000))
|
|
}
|
|
}
|
|
console.log(` Zoo C-Chain block: ${block.toLocaleString()}`)
|
|
expect(block).toBeGreaterThan(0)
|
|
})
|
|
|
|
test('Zoo C-Chain returns correct chain ID', async ({ request }) => {
|
|
try {
|
|
const cid = await ethChainId(request, APPCHAIN_RPCS.zoo)
|
|
console.log(` Zoo chain ID: ${cid} (expected: ${chainIds.zoo})`)
|
|
expect(cid).toBe(chainIds.zoo)
|
|
} catch {
|
|
console.log(' Zoo chain ID query failed (RPC may be throttled)')
|
|
}
|
|
})
|
|
|
|
test('Zoo C-Chain is producing blocks', async ({ request }) => {
|
|
let block1 = 0
|
|
let block2 = 0
|
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
try {
|
|
block1 = await ethBlockNumber(request, APPCHAIN_RPCS.zoo)
|
|
break
|
|
} catch {
|
|
if (attempt < 2) await new Promise(r => setTimeout(r, 1000))
|
|
}
|
|
}
|
|
await new Promise(r => setTimeout(r, 3000))
|
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
try {
|
|
block2 = await ethBlockNumber(request, APPCHAIN_RPCS.zoo)
|
|
break
|
|
} catch {
|
|
if (attempt < 2) await new Promise(r => setTimeout(r, 1000))
|
|
}
|
|
}
|
|
console.log(` Zoo blocks: ${block1} -> ${block2}`)
|
|
expect(block2).toBeGreaterThanOrEqual(block1)
|
|
})
|
|
})
|
|
|
|
// ── Hanzo C-Chain ──────────────────────────────────────────────────
|
|
test.describe('App Chains — Hanzo', () => {
|
|
test('Hanzo C-Chain RPC responds', async ({ request }) => {
|
|
if (!('hanzo' in APPCHAIN_RPCS)) {
|
|
test.skip(true, 'Hanzo RPC not configured in local mode')
|
|
}
|
|
const rpc = (APPCHAIN_RPCS as Record<string, string>).hanzo
|
|
try {
|
|
const block = await ethBlockNumber(request, rpc)
|
|
console.log(` Hanzo C-Chain block: ${block.toLocaleString()}`)
|
|
expect(block).toBeGreaterThan(0)
|
|
} catch {
|
|
console.log(' Hanzo C-Chain RPC not reachable (chain may not be deployed yet)')
|
|
}
|
|
})
|
|
|
|
test('Hanzo C-Chain returns correct chain ID', async ({ request }) => {
|
|
if (!('hanzo' in APPCHAIN_RPCS)) {
|
|
test.skip(true, 'Hanzo RPC not configured in local mode')
|
|
}
|
|
const rpc = (APPCHAIN_RPCS as Record<string, string>).hanzo
|
|
try {
|
|
const cid = await ethChainId(request, rpc)
|
|
console.log(` Hanzo chain ID: ${cid} (expected: ${chainIds.hanzo})`)
|
|
expect(cid).toBe(chainIds.hanzo)
|
|
} catch {
|
|
console.log(' Hanzo chain ID query failed')
|
|
}
|
|
})
|
|
})
|
|
|
|
// ── SPC C-Chain ────────────────────────────────────────────────────
|
|
test.describe('App Chains — SPC', () => {
|
|
test('SPC C-Chain RPC responds', async ({ request }) => {
|
|
if (!('spc' in APPCHAIN_RPCS)) {
|
|
test.skip(true, 'SPC RPC not configured in local mode')
|
|
}
|
|
const rpc = (APPCHAIN_RPCS as Record<string, string>).spc
|
|
try {
|
|
const block = await ethBlockNumber(request, rpc)
|
|
console.log(` SPC C-Chain block: ${block.toLocaleString()}`)
|
|
expect(block).toBeGreaterThan(0)
|
|
} catch {
|
|
console.log(' SPC C-Chain RPC not reachable (chain may not be deployed yet)')
|
|
}
|
|
})
|
|
|
|
test('SPC C-Chain returns correct chain ID', async ({ request }) => {
|
|
if (!('spc' in APPCHAIN_RPCS)) {
|
|
test.skip(true, 'SPC RPC not configured in local mode')
|
|
}
|
|
const rpc = (APPCHAIN_RPCS as Record<string, string>).spc
|
|
try {
|
|
const cid = await ethChainId(request, rpc)
|
|
console.log(` SPC chain ID: ${cid} (expected: ${chainIds.spc})`)
|
|
expect(cid).toBe(chainIds.spc)
|
|
} catch {
|
|
console.log(' SPC chain ID query failed')
|
|
}
|
|
})
|
|
})
|
|
|
|
// ── Pars C-Chain ───────────────────────────────────────────────────
|
|
test.describe('App Chains — Pars', () => {
|
|
test('Pars C-Chain RPC responds', async ({ request }) => {
|
|
if (!('pars' in APPCHAIN_RPCS)) {
|
|
test.skip(true, 'Pars RPC not configured in local mode')
|
|
}
|
|
const rpc = (APPCHAIN_RPCS as Record<string, string>).pars
|
|
try {
|
|
const block = await ethBlockNumber(request, rpc)
|
|
console.log(` Pars C-Chain block: ${block.toLocaleString()}`)
|
|
expect(block).toBeGreaterThan(0)
|
|
} catch {
|
|
console.log(' Pars C-Chain RPC not reachable (chain may not be deployed yet)')
|
|
}
|
|
})
|
|
|
|
test('Pars C-Chain returns correct chain ID', async ({ request }) => {
|
|
if (!('pars' in APPCHAIN_RPCS)) {
|
|
test.skip(true, 'Pars RPC not configured in local mode')
|
|
}
|
|
const rpc = (APPCHAIN_RPCS as Record<string, string>).pars
|
|
try {
|
|
const cid = await ethChainId(request, rpc)
|
|
console.log(` Pars chain ID: ${cid} (expected: ${chainIds.pars})`)
|
|
expect(cid).toBe(chainIds.pars)
|
|
} catch {
|
|
console.log(' Pars chain ID query failed')
|
|
}
|
|
})
|
|
})
|
|
|
|
// ── Cross-Chain Block Production ──────────────────────────────────
|
|
test.describe('App Chains — Cross-Chain Block Comparison', () => {
|
|
test('all app chain explorers report blocks', async ({ request }) => {
|
|
for (const { name, api } of EXPLORERS.filter((e) => e.org !== 'lux')) {
|
|
try {
|
|
const data = await httpGetJson(request, `${api}/stats`) as Record<string, unknown>
|
|
const blocks = Number(data.total_blocks || 0)
|
|
const txs = Number(data.total_transactions || 0)
|
|
console.log(` ${name}: ${blocks} blocks, ${txs} txs`)
|
|
expect(blocks).toBeGreaterThan(0)
|
|
} catch {
|
|
console.log(` ${name}: explorer not reachable`)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
// ── Registered Blockchains ─────────────────────────────────────────
|
|
test.describe('App Chains — Registered Blockchains', () => {
|
|
test('P-Chain lists all expected chains', async ({ request }) => {
|
|
const result = await rpcCall(
|
|
request, urls.rpcPlatform, 'platform.getBlockchains', {},
|
|
) as { blockchains: { name: string; id: string; netID: string; vmID: string }[] }
|
|
const chains = result.blockchains
|
|
console.log(` Registered blockchains: ${chains.length}`)
|
|
for (const chain of chains) {
|
|
console.log(` ${chain.name}: id=${chain.id} net=${chain.netID}`)
|
|
}
|
|
// At minimum: C-Chain, X-Chain, and D (P-Chain internal)
|
|
expect(chains.length).toBeGreaterThanOrEqual(3)
|
|
})
|
|
|
|
test('blockchains have unique IDs', async ({ request }) => {
|
|
const result = await rpcCall(
|
|
request, urls.rpcPlatform, 'platform.getBlockchains', {},
|
|
) as { blockchains: { id: string }[] }
|
|
const ids = result.blockchains.map(c => c.id)
|
|
const unique = new Set(ids)
|
|
expect(unique.size).toBe(ids.length)
|
|
console.log(` All ${ids.length} blockchain IDs are unique`)
|
|
})
|
|
})
|