1<!doctype html> 2<html lang="en"> 3<head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 <title>Masternode + Quorum Health | Smartiecoin (SMT)</title> 7 <meta name="description" content="Live masternode and LLMQ quorum health for the Smartiecoin (SMT) network: node counts, DKG sessions, active quorums, and progress toward 100-node milestones."> 8 <meta name="theme-color" content="#0a0a0b"> 9 <meta property="og:type" content="website"> 10 <meta property="og:title" content="Smartiecoin Masternode + Quorum Health"> 11 <meta property="og:description" content="Live masternode and LLMQ quorum health for the Smartiecoin network."> 12 <meta property="og:image" content="https://smartiecoin.com/assets/logo-social.png"> 13 <meta property="og:image:width" content="1200"> 14 <meta property="og:image:height" content="630"> 15 <meta property="og:image:alt" content="Smartiecoin logo"> 16 <meta property="og:url" content="https://smartiecoin.com/masternodes.html"> 17 <meta name="twitter:card" content="summary_large_image"> 18 <meta name="twitter:image" content="https://smartiecoin.com/assets/logo-social.png"> 19 <meta name="twitter:image:alt" content="Smartiecoin logo"> 20 <link rel="icon" type="image/png" sizes="64x64" href="assets/favicon.png"> 21 <link rel="apple-touch-icon" href="assets/logo-mark.png"> 22 <link rel="preconnect" href="https://fonts.googleapis.com"> 23 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 24 <link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet"> 25 <link rel="stylesheet" href="styles.css"> 26 27</head> 28<body> 29 <a class="skip-link" href="#main">Skip to content</a> 30 31 32 <header class="site-header"> 33 <div class="container header-row"> 34 <a class="brand" href="index.html"> 35 <img class="brand-logo" src="assets/logo-mark.png" alt="Smartiecoin logo" width="30" height="30"> 36 <span>Smartiecoin</span> 37 <strong>SMT</strong> 38 </a> 39 40 <button class="menu-toggle" type="button" aria-expanded="false" aria-controls="primary-nav">Menu</button> 41 42 <nav id="primary-nav" class="nav-links" aria-label="Primary"> 43 <a href="index.html#snapshot">Snapshot</a> 44 <a href="index.html#tokenomics">Tokenomics</a> 45 <a href="index.html#live">Live Stats</a> 46 <a href="index.html#tech">Technology</a> 47 <a href="masternodes.html" aria-current="page">Masternodes</a> 48 <a href="https://explorer.smartiecoin.com/mempool/" target="_blank" rel="noopener">Mempool â</a> 49 <a href="index.html#links">Links</a> 50 </nav> 51 </div> 52 </header> 53 54 <main id="main"> 55 <section class="mn-hero"> 56 <div class="container"> 57 <p class="eyebrow">Network Health</p> 58 <h1>Masternode + Quorum Dashboard</h1> 59 <p class="lead"> 60 Live snapshot of the Smartiecoin masternode set and LLMQ quorum health. This page tracks 61 node counts, active quorums, and DKG sessions as the network grows toward the thresholds 62 required to activate InstantSend, ChainLocks, and platform quorums at scale. 63 </p> 64 <div class="mn-meta"> 65 <span><span id="freshness-dot" class="dot"></span><span id="freshness-label">Loading...</span></span> 66 <span>Source: <code>smartiecoin-cli</code> on a synced node</span> 67 <span>Updated: <span id="fetched-at">-</span></span> 68 <span>Auto-refresh: <span id="refresh-countdown">60s</span></span> 69 </div> 70 </div> 71 </section> 72 73 <section class="section"> 74 <div class="container"> 75 <div class="mn-grid" id="stat-cards"> 76 <article class="card mn-stat accent-orange"> 77 <span class="label">Enabled Nodes</span> 78 <div class="value"><span id="stat-enabled" class="skeleton">--</span></div> 79 <div class="sub"><span id="stat-total">total --</span></div> 80 </article> 81 <article class="card mn-stat accent-sky"> 82 <span class="label">Evo Nodes</span> 83 <div class="value"><span id="stat-evo" class="skeleton">--</span></div> 84 <div class="sub">75,000 SMT collateral</div> 85 </article> 86 <article class="card mn-stat accent-mint">
87 <span class="label">Regular Nodes</span> 88 <div class="value"><span id="stat-regular" class="skeleton">--</span></div> 89 <div class="sub">15,000 SMT collateral</div> 90 </article> 91 <article class="card mn-stat accent-violet"> 92 <span class="label">DKG Sessions</span> 93 <div class="value"><span id="stat-dkg" class="skeleton">--</span></div> 94 <div class="sub"><span id="stat-dkg-sub">monitoring--</span></div> 95 </article> 96 </div> 97 </div> 98 </section> 99 100 <section class="section"> 101 <div class="container"> 102 <article class="card mn-progress-card"> 103 <div class="mn-progress-head"> 104 <h3>Network Growth - Milestones</h3> 105 <span class="pct"><span id="progress-nodes" class="skeleton">--</span> nodes</span> 106 </div> 107 <div class="mn-progress-track"> 108 <div class="mn-progress-bar" id="progress-bar"></div> 109 <div class="mn-progress-ticks" id="progress-ticks"></div> 110 </div> 111 <div class="mn-progress-scale" id="progress-scale"></div> 112 <div class="mn-milestones" id="progress-milestones"></div> 113 <p class="mn-progress-foot"> 114 <span id="progress-foot">Each milestone unlocks a stronger LLMQ. Regular (15k SMT) and Evo (75k SMT) nodes count equally toward all of them.</span> 115 </p> 116 </article> 117 </div> 118 </section> 119 120 <section class="section"> 121 <div class="container"> 122 <div class="mn-grid-2 mn-grid"> 123 <article class="card quorum-list"> 124 <h3>Active Quorums</h3> 125 <div id="quorum-rows"> 126 <div class="quorum-row is-empty"> 127 <span class="q-name skeleton">LLMQ_TYPE</span> 128 <span class="q-count skeleton">-</span> 129 <span class="q-bar"><span style="width: 0%"></span></span> 130 <span class="q-status off">...</span> 131 </div> 132 </div> 133 </article> 134 135 <article class="card dkg-card"> 136 <h3>DKG Health</h3> 137 <p class="sub">Distributed Key Generation stats across currently forming quorums.</p> 138 <div class="dkg-metrics"> 139 <div class="m" id="dkg-sessions-box"> 140 <div class="k">Sessions</div> 141 <div class="v"><span id="dkg-sessions" class="skeleton">-</span></div> 142 </div> 143 <div class="m" id="dkg-bad-box"> 144 <div class="k">Worst Bad Members</div> 145 <div class="v"><span id="dkg-bad" class="skeleton">-</span></div> 146 </div> 147 <div class="m" id="dkg-commits-box"> 148 <div class="k">Premature Commits</div> 149 <div class="v"><span id="dkg-commits" class="skeleton">-</span></div> 150 </div> 151 </div> 152 <ul class="dkg-sessions" id="dkg-list"> 153 <li><span class="q skeleton">LLMQ_TYPE idx -</span><span class="phase skeleton">phase -</span><span class="bad skeleton">bad -</span></li> 154 </ul> 155 </article> 156 </div> 157 158 <div id="notice" class="mn-note" hidden></div> 159 </div> 160 </section> 161 162 <section class="section"> 163 <div class="container"> 164 <div class="section-head"> 165 <h2>What these numbers mean</h2> 166 <p> 167 <strong>Regular and Evo masternodes participate equally</strong> in every quorum that 168 matters for day-to-day network operation - ChainLocks, InstantSend, and hard-fork 169 signaling. The collateral difference (15k SMT for Regular, 75k SMT for Evo) only changes 170 the masternode role; it doesn't make Evo nodes "count more" in these LLMQs. The single 171 exception is Smartiecoin Platform (LLMQ_100_67), which is Evo-only - and Platform is 172 <strong>not a current network priority</strong>. 173 </p> 174 <p style="margin-top: 0.6rem;"> 175 Because Regular nodes cost 5x less collateral, they are the most cost-effective way to 176 grow the network and stabilize the LLMQs that secure transactions and finality today. 177 When <strong>Bad Members</strong> in a DKG session rise close to the quorum size, the 178 session can fail - this is expected while the network is still growing. 179 </p> 180 </div> 181 <div class="cards cards-2"> 182 <article class="card"> 183 <h3>Raw Data</h3> 184 <p> 185 All data on this page comes from <code>smartiecoin-cli</code> on a synced full node 186 (<code>
186masternode count</code>, <code>masternodelist json</code>, <code>quorum list</code>, 187 <code>quorum dkgstatus</code>) and is refreshed every minute. 188 </p> 189 <p style="margin-top: 0.6rem;"> 190 <a class="btn btn-soft" href="assets/quorum-health.json" target="_blank" rel="noopener">View JSON</a> 191 </p> 192 </article> 193 <article class="card"> 194 <h3>Run Your Own Masternode</h3> 195 <p> 196 Grow the network and help stabilize quorums. Check the repository for setup guides, 197 the required collateral, and the <code>protx register_prepare</code> flow. 198 </p> 199 <p style="margin-top: 0.6rem;"> 200 <a class="btn btn-soft" href="https://github.com/SmartiesCoin/Smartiecoin" target="_blank" rel="noopener">Smartiecoin on GitHub</a> 201 </p> 202 </article> 203 </div> 204 </div> 205 </section> 206 </main> 207 208 <footer class="site-footer"> 209 <div class="container footer-row"> 210 <p>Smartiecoin (SMT) - Live network health from the official full node.</p> 211 <p><span id="year"></span> smartiecoin.com · <a href="https://explorer.smartiecoin.com/mempool/" target="_blank" rel="noopener">Mempool</a></p> 212 </div> 213 </footer> 214 215
215<script> 216 (function () { 217 var DATA_URL = 'https://explorer.smartiecoin.com/quorum-health.json'; 218 var FALLBACK_URL = 'assets/quorum-health.json'; 219 var REFRESH_MS = 60 * 1000; 220 var STALE_AFTER_MIN = 10; 221 222 // Each LLMQ is described by what it does on the Smartiecoin network and 223 // whether it's a current priority. "inactive" means the chain knows about 224 // it but it's not part of the current activation roadmap. 225 // The "target" is signingActiveQuorumCount from src/llmq/params.h - the 226 // number of recent quorums of this type kept active for signing. 227 var QUORUM_META = { 228 llmq_10_60: { label: 'LLMQ_10_60', target: 4, purpose: 'ChainLocks - 10-member quorums for small networks', status: 'active' }, 229 llmq_10_75: { label: 'LLMQ_10_75', target: 2, purpose: 'InstantSend - 10-member rotated quorums for small networks', status: 'active' }, 230 llmq_60_75: { label: 'LLMQ_60_75', target: 32, purpose: 'InstantSend DIP0024 - 60-member rotated quorums', status: 'active' }, 231 llmq_400_60: { label: 'LLMQ_400_60', target: 4, purpose: 'ChainLocks at scale - 400-member quorums', status: 'pending' }, 232 llmq_400_85: { label: 'LLMQ_400_85', target: 4, purpose: 'Hard-fork signaling (MNHF) - 400-member quorums', status: 'pending' }, 233 llmq_100_67: { label: 'LLMQ_100_67', target: 24, purpose: 'Smartiecoin Platform - not a current priority', status: 'inactive' } 234 }; 235 236 var $ = function (id) { return document.getElementById(id); }; 237 238 function fmtNum(n) { 239 if (n === null || n === undefined || isNaN(n)) return '-'; 240 return Number(n).toLocaleString('en-US'); 241 } 242 243 function clearSkeleton(el) { 244 if (el) el.classList.remove('skeleton'); 245 } 246 247 function setText(id, text) { 248 var el = $(id); 249 if (!el) return; 250 el.textContent = text; 251 clearSkeleton(el); 252 } 253 254 function minutesSince(iso) { 255 if (!iso) return Infinity; 256 var t = Date.parse(iso); 257 if (isNaN(t)) return Infinity; 258 return (Date.now() - t) / 60000; 259 } 260 261 function fmtAgo(iso) { 262 var mins = minutesSince(iso); 263 if (!isFinite(mins)) return 'never'; 264 if (mins < 1) return 'just now'; 265 if (mins < 60) return Math.round(mins) + ' min ago'; 266 var hrs = mins / 60; 267 if (hrs < 24) return Math.round(hrs) + ' hr ago'; 268 return Math.round(hrs / 24) + ' d ago'; 269 } 270 271 function setFreshness(iso, isError) { 272 var dot = $('freshness-dot'); 273 var label = $('freshness-label'); 274 dot.classList.remove('stale', 'down'); 275 if (isError || !iso) { 276 dot.classList.add('down'); 277 label.textContent = 'Data unavailable'; 278 return; 279 } 280 var mins = minutesSince(iso); 281 if (mins > STALE_AFTER_MIN) { 282 dot.classList.add('stale'); 283 label.textContent = 'Data is stale (' + fmtAgo(iso) + ')'; 284 } else { 285 label.textContent = 'Live'; 286 } 287 } 288 289 function showNotice(msg, isError) { 290 var n = $('notice'); 291 n.hidden = false; 292 n.textContent = msg; 293 n.classList.toggle('mn-error', !!isError); 294 } 295 296 function hideNotice() { 297 $('notice').hidden = true; 298 } 299
300 function renderStats(data) { 301 var nodes = data.nodes || {}; 302 setText('stat-enabled', fmtNum(nodes.enabled)); 303 var totalEl = $('stat-total'); 304 totalEl.textContent = 'total ' + fmtNum(nodes.total); 305 setText('stat-evo', fmtNum(nodes.evo)); 306 setText('stat-regular', fmtNum(nodes.regular)); 307 308 var dkg = data.dkg || {}; 309 setText('stat-dkg', fmtNum(dkg.sessions_count)); 310 var subEl = $('stat-dkg-sub'); 311 var bad = dkg.worst_bad_members || 0; 312 var commits = dkg.total_premature_commits || 0; 313 subEl.textContent = 'worst bad: ' + bad + ' | commits: ' + commits; 314 } 315 316 var MILESTONES = [ 317 { nodes: 60, title: 'InstantSend DIP0024', sub: 'LLMQ_60_75 reliable at 60 nodes' }, 318 { nodes: 100, title: 'Platform possible', sub: 'LLMQ_100_67 - optional, Evo-only' }, 319 { nodes: 400, title: 'Full ChainLocks + MNHF', sub: 'LLMQ_400_60 / LLMQ_400_85 at scale' } 320 ]; 321 var MILESTONE_MAX = 400; 322 323 function renderProgress(data) { 324 var nodes = data.nodes || {}; 325 var enabled = nodes.enabled || 0; 326 327 var fillPct = Math.max(0, Math.min(100, (enabled / MILESTONE_MAX) * 100)); 328 setText('progress-nodes', enabled.toString()); 329 $('progress-bar').style.width = fillPct + '%'; 330 331 var ticks = $('progress-ticks'); 332 var scale = $('progress-scale'); 333 var cards = $('progress-milestones'); 334 ticks.innerHTML = ''; 335 scale.innerHTML = ''; 336 cards.innerHTML = ''; 337 338 MILESTONES.forEach(function (m) { 339 var left = (m.nodes / MILESTONE_MAX) * 100; 340 var reached = enabled >= m.nodes; 341 342 var tick = document.createElement('span'); 343 if (reached) tick.className = 'reached'; 344 tick.style.left = left + '%'; 345 ticks.appendChild(tick); 346 347 var num = document.createElement('span'); 348 if (reached) num.className = 'reached'; 349 num.style.left = left + '%'; 350 num.textContent = m.nodes; 351 scale.appendChild(num); 352 353 var card = document.createElement('div'); 354 card.className = 'mn-ms-card' + (reached ? ' reached' : '');
355 var statusCls = reached ? 'reached' : 'pending'; 356 var statusTxt = reached ? 'REACHED' : 'PENDING'; 357 card.innerHTML = 358 '<span class="ms-num">' + m.nodes + '</span>' + 359 '<div class="ms-body">' + 360 '<div class="ms-title">' + m.title + '</div>' + 361 '<div class="ms-sub">' + m.sub + '</div>' + 362 '</div>' + 363 '<span class="ms-status ' + statusCls + '">' + statusTxt + '</span>'; 364 cards.appendChild(card); 365 }); 366 367 var next = null; 368 for (var i = 0; i < MILESTONES.length; i++) { 369 if (enabled < MILESTONES[i].nodes) { next = MILESTONES[i]; break; } 370 } 371 var foot; 372 if (!next) { 373 foot = 'All network growth milestones reached. The chain can form every LLMQ type reliably.'; 374 } else { 375 var remaining = next.nodes - enabled; 376 foot = 'Next milestone: ' + next.nodes + ' nodes (' + remaining + ' more to go) - ' + next.title + '.'; 377 } 378 $('progress-foot').textContent = foot; 379 } 380 381 function renderQuorums(data) { 382 var container = $('quorum-rows'); 383 container.innerHTML = ''; 384 var quorums = data.quorums || []; 385 386 var known = Object.keys(QUORUM_META); 387 var byType = {}; 388 quorums.forEach(function (q) { 389 byType[q.type] = q; 390 }); 391 known.forEach(function (t) { 392 if (!byType[t]) byType[t] = { type: t, active_count: 0 }; 393 }); 394 395 known.forEach(function (t) { 396 var q = byType[t]; 397 var meta = QUORUM_META[t] || { label: t.toUpperCase(), target: 4, purpose: '', status: 'active' }; 398 var count = q.active_count || 0; 399 var target = meta.target || 4; 400 var pct = Math.max(0, Math.min(100, Math.round((count / target) * 100))); 401 402 var statusClass, statusText; 403 if (meta.status === 'inactive') { 404 statusClass = 'inactive'; 405 statusText = 'NOT A PRIORITY'; 406 } else if (count >= target) { 407 statusClass = 'ok'; 408 statusText = 'HEALTHY'; 409 } else if (count > 0) { 410 statusClass = 'warn'; 411 statusText = 'FORMING'; 412 } else if (meta.status === 'pending') { 413 statusClass = 'off'; 414 statusText = 'WAITING ON GROWTH'; 415 } else { 416 statusClass = 'off'; 417 statusText = 'EMPTY'; 418 } 419 420 var rowClass = 'quorum-row'; 421 if (count === 0) rowClass += ' is-empty'; 422 if (meta.status === 'inactive') rowClass += ' is-inactive'; 423 424 var row = document.createElement('div'); 425 row.className = rowClass; 426 row.innerHTML = 427 '<span class="q-name-wrap">' + 428 '<span class="q-name">' + meta.label + '</span>' + 429 (meta.purpose ? '<span class="q-purpose">' + meta.purpose + '</span>' : '') + 430 '</span>' + 431 '<span class="q-count">' + count + ' / ' + target + '</span>' + 432 '<span class="q-bar"><span style="width:' + pct + '%"></span></span>' + 433 '<span class="q-status ' + statusClass + '">' + statusText + '</span>'; 434 container.appendChild(row); 435 }); 436 } 437 438 function renderDkg(data) { 439 var dkg = data.dkg || {}; 440 setText('dkg-sessions', fmtNum(dkg.sessions_count)); 441 setText('dkg-bad', fmtNum(dkg.worst_bad_members)); 442 setText('dkg-commits', fmtNum(dkg.total_premature_commits)); 443 444 var badBox = $('dkg-bad-box'); 445 badBox.classList.remove('warn', 'ok'); 446 if ((dkg.worst_bad_members || 0) >= 10) badBox.classList.add('warn'); 447 else if ((dkg.sessions_count || 0) > 0) badBox.classList.add('ok'); 448 449 var list = $('dkg-list'); 450 list.innerHTML = ''; 451 var sessions = dkg.sessions || []; 452 if (!sessions.length) { 453 var li = document.createElement('li'); 454 li.innerHTML = '<span class="q">No active DKG sessions</span><span class="phase">-</span><span class="bad">-</span>'; 455 list.appendChild(li); 456 return; 457 } 458 sessions.forEach(function (s) { 459 var typeKey = 'llmq_' + (s.llmqType || 'unknown'); 460 var label = (QUORUM_META[typeKey] && QUORUM_META[typeKey].label) || ('Type ' + s.llmqType); 461 var li = document.createElement('li'); 462 if ((s.badMembers || 0) >= 10) li.className = 'is-bad'; 463 li.innerHTML = 464 '<span class="q">' + label + ' idx ' + (s.quorumIndex != null ? s.quorumIndex : '-') + (s.aborted ? ' (aborted)' : '') + '</span>' + 465 '<span class="phase">phase ' + (s.phase != null ? s.phase : '-') + '</span>' + 466 '<span class="bad">bad ' + (s.badMembers || 0) + '</span>'; 467 list.appendChild(li); 468 }); 469 } 470 471 function renderAll(data) { 472 renderStats(data); 473 renderProgress(data); 474 renderQuorums(data); 475 renderDkg(data); 476 $('fetched-at').textContent = fmtAgo(data.fetched_at); 477 setFreshness(data.fetched_at, false); 478 } 479 480 function renderError() { 481 ['stat-enabled','stat-evo','stat-regular','stat-dkg','progress-nodes','dkg-sessions','dkg-bad','dkg-commits'].forEach(function (id) { 482 var el = $(id); 483 if (el) { el.textContent = '-'; clearSkeleton(el); } 484 }); 485 $('progress-bar').style.width = '0%'; 486 $('quorum-rows').innerHTML = '<div class="quorum-row is-empty"><span class="q-name">No data</span><span class="q-count">-</span><span class="q-bar"><span style="width:0%"></span></span><span class="q-status off">OFFLINE</span></div>'; 487 $('dkg-list').innerHTML = '<li><span class="q">Data unavailable</span><span class="phase">-</span><span class="bad">-</span></li>'; 488 $('fetched-at').textContent = 'never'; 489 setFreshness(null, true); 490 showNotice('Could not load quorum data. The snapshot job may be warming up or the VPS may be offline.', true); 491 } 492 493 function fetchJson(url) { 494 return fetch(url, { cache: 'no-store' }).then(function (r) { 495 if (!r.ok) throw new Error('HTTP ' + r.status); 496 return r.json(); 497 }); 498 } 499 500 function load() { 501 fetchJson(DATA_URL) 502 .catch(function () { return fetchJson(FALLBACK_URL); }) 503 .then(function (data) { 504 hideNotice(); 505 renderAll(data); 506 if (data.placeholder) { 507 showNotice('Showing fallback snapshot. The live explorer feed
507is temporarily unavailable.', false); 508 } 509 }) 510 .catch(function () { 511 renderError(); 512 }); 513 } 514 515 var countdown = REFRESH_MS / 1000; 516 setInterval(function () { 517 countdown -= 1; 518 if (countdown <= 0) countdown = REFRESH_MS / 1000; 519 $('refresh-countdown').textContent = countdown + 's'; 520 }, 1000); 521 522 load(); 523 setInterval(load, REFRESH_MS); 524 525 $('year').textContent = new Date().getFullYear(); 526 527 var menuBtn = document.querySelector('.menu-toggle'); 528 var nav = document.getElementById('primary-nav'); 529 if (menuBtn && nav) { 530 menuBtn.addEventListener('click', function () { 531 var open = menuBtn.getAttribute('aria-expanded') === 'true'; 532 menuBtn.setAttribute('aria-expanded', open ? 'false' : 'true'); 533 nav.classList.toggle('is-open', !open); 534 }); 535 } 536 })(); 537 </script>
537 538</body> 539</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.