Files
dchain/node/explorer/validators.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

59 lines
2.0 KiB
JavaScript

(function() {
var C = window.ExplorerCommon;
async function loadValidators() {
C.setStatus('Loading…', 'warn');
try {
var data = await C.fetchJSON('/api/validators');
var validators = (data && Array.isArray(data.validators)) ? data.validators : [];
var quorum = validators.length > 0 ? Math.floor(2 * validators.length / 3) + 1 : 0;
document.getElementById('valCount').textContent = validators.length;
document.getElementById('quorumCount').textContent = quorum || '—';
var tbody = document.getElementById('valBody');
if (!validators.length) {
tbody.innerHTML = '<tr><td colspan="4" class="tbl-empty">No validators found.</td></tr>';
C.setStatus('No validators registered.', 'warn');
return;
}
var rows = '';
validators.forEach(function(v, i) {
var addr = v.address || '—';
var pubKey = v.pub_key || '—';
rows +=
'<tr>' +
'<td class="text-muted" style="font-size:12px">' + (i + 1) + '</td>' +
'<td>' +
'<a class="mono" href="/address?address=' + encodeURIComponent(pubKey) + '">' +
C.esc(addr) +
'</a>' +
'</td>' +
'<td class="mono" style="color:var(--muted);font-size:12px">' +
C.esc(C.short(pubKey, 32)) +
'</td>' +
'<td>' +
'<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(
validators.length + ' validator' + (validators.length !== 1 ? 's' : '') +
' · quorum: ' + quorum,
'ok'
);
C.refreshIcons();
} catch (e) {
C.setStatus('Load failed: ' + e.message, 'err');
}
}
document.getElementById('refreshBtn').addEventListener('click', loadValidators);
loadValidators();
})();