Files
dchain/node/explorer/relays.js
vsecoder 7e7393e4f8 chore: initial commit for v0.0.1
DChain single-node blockchain + React Native messenger client.

Core:
- PBFT consensus with multi-sig validator admission + equivocation slashing
- BadgerDB + schema migration scaffold (CurrentSchemaVersion=0)
- libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1)
- Native Go contracts (username_registry) alongside WASM (wazero)
- WebSocket gateway with topic-based fanout + Ed25519-nonce auth
- Relay mailbox with NaCl envelope encryption (X25519 + Ed25519)
- Prometheus /metrics, per-IP rate limit, body-size cap

Deployment:
- Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus
- 3-node dev compose (docker-compose.yml) with mocked internet topology
- 3-validator prod compose (deploy/prod/) for federation
- Auto-update from Gitea via /api/update-check + systemd timer
- Build-time version injection (ldflags → node --version)
- UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER)

Client (client-app/):
- Expo / React Native / NativeWind
- E2E NaCl encryption, typing indicator, contact requests
- Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch

Documentation:
- README.md, CHANGELOG.md, CONTEXT.md
- deploy/single/README.md with 6 operator scenarios
- deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design
- docs/contracts/*.md per contract
2026-04-17 14:16:44 +03:00

69 lines
2.5 KiB
JavaScript

(function() {
var C = window.ExplorerCommon;
function fmtFee(ut) {
if (!ut) return '<span class="text-muted">Free</span>';
if (ut < 1000) return ut + ' µT';
return C.toToken(ut);
}
async function loadRelays() {
C.setStatus('Loading…', 'warn');
try {
var data = await C.fetchJSON('/api/relays');
var relays = Array.isArray(data) ? data : [];
document.getElementById('relayCount').textContent = relays.length;
var tbody = document.getElementById('relayBody');
if (!relays.length) {
tbody.innerHTML = '<tr><td colspan="6" class="tbl-empty">No relay nodes registered yet.</td></tr>';
C.setStatus('No relay nodes found.', 'warn');
return;
}
var rows = '';
relays.forEach(function(info, i) {
var pubKey = info.pub_key || '';
var addr = info.address || '—';
var x25519 = (info.relay && info.relay.x25519_pub_key) || '—';
var feeUT = (info.relay && info.relay.fee_per_msg_ut) || 0;
var multiaddr = (info.relay && info.relay.multiaddr) || '';
rows +=
'<tr>' +
'<td class="text-muted" style="font-size:12px">' + (i + 1) + '</td>' +
'<td>' +
(pubKey
? '<a class="mono" href="/address?address=' + encodeURIComponent(pubKey) + '">' + C.esc(addr) + '</a>'
: C.esc(addr)) +
'</td>' +
'<td class="mono" style="font-size:11px;color:var(--muted)">' +
C.esc(C.short(x25519, 28)) +
'</td>' +
'<td>' + fmtFee(feeUT) + '</td>' +
'<td class="mono" style="font-size:11px;color:var(--muted);max-width:200px;overflow:hidden;text-overflow:ellipsis">' +
(multiaddr ? C.esc(multiaddr) : '<span class="text-muted">—</span>') +
'</td>' +
'<td>' +
(pubKey
? '<a href="/node?node=' + encodeURIComponent(pubKey) + '" class="pill-link" style="font-size:12px;padding:4px 10px">' +
'<i data-lucide="server"></i> Node' +
'</a>'
: '') +
'</td>' +
'</tr>';
});
tbody.innerHTML = rows;
C.setStatus(relays.length + ' relay node' + (relays.length !== 1 ? 's' : '') + ' registered.', 'ok');
C.refreshIcons();
} catch (e) {
C.setStatus('Load failed: ' + e.message, 'err');
}
}
document.getElementById('refreshBtn').addEventListener('click', loadRelays);
loadRelays();
})();