blockyard 0.0.1 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +679 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +4 -0
  4. package/README.md +172 -4
  5. package/SECURITY.md +38 -0
  6. package/bin/blockyard.js +40 -0
  7. package/config/pool-map.json +2620 -0
  8. package/docs/API.md +1575 -0
  9. package/docs/ARCHITECTURE.md +1307 -0
  10. package/docs/AUTO-UPDATE.md +269 -0
  11. package/docs/CONFIGURATION.md +840 -0
  12. package/docs/DEFECTS.md +813 -0
  13. package/docs/EFFECTS-AGENTS.md +448 -0
  14. package/docs/GETTING-STARTED.md +202 -0
  15. package/docs/INSTALL.md +490 -0
  16. package/docs/MEASUREMENTS.md +1254 -0
  17. package/docs/PRIVATE-LEADERBOARD.md +230 -0
  18. package/docs/RULES.md +681 -0
  19. package/docs/SECURITY-AUDIT-2026-09-14.md +177 -0
  20. package/docs/SECURITY-AUDIT.md +258 -0
  21. package/docs/SECURITY.md +195 -0
  22. package/docs/STATE-2026-09-09.md +200 -0
  23. package/docs/TROUBLESHOOTING.md +298 -0
  24. package/docs/USER-GUIDE.md +1022 -0
  25. package/package.json +53 -5
  26. package/public/404.html +9 -0
  27. package/public/css/app.css +1785 -0
  28. package/public/index.html +893 -0
  29. package/public/js/about.js +112 -0
  30. package/public/js/agents.js +964 -0
  31. package/public/js/app.js +1312 -0
  32. package/public/js/arkanoid.js +806 -0
  33. package/public/js/blockanoid.js +347 -0
  34. package/public/js/blockout.js +347 -0
  35. package/public/js/blockpack.js +428 -0
  36. package/public/js/blockscene3d.js +2678 -0
  37. package/public/js/breakout.js +224 -0
  38. package/public/js/charts.js +635 -0
  39. package/public/js/depthchart.js +311 -0
  40. package/public/js/details3d.js +2957 -0
  41. package/public/js/explorer.js +405 -0
  42. package/public/js/feepalette.js +149 -0
  43. package/public/js/fmt.js +162 -0
  44. package/public/js/goggles.js +886 -0
  45. package/public/js/kiosk.js +41 -0
  46. package/public/js/login.js +83 -0
  47. package/public/js/markets.js +357 -0
  48. package/public/js/mining.js +1138 -0
  49. package/public/js/panels.js +966 -0
  50. package/public/js/pricechart.js +188 -0
  51. package/public/js/settings.js +1014 -0
  52. package/public/js/tetris.js +226 -0
  53. package/public/js/tetrust.js +356 -0
  54. package/public/js/tetsound.js +175 -0
  55. package/public/login.html +33 -0
  56. package/scripts/blockfile-measure.js +156 -0
  57. package/scripts/browser-check.mjs +286 -0
  58. package/scripts/check.js +173 -0
  59. package/scripts/decode-check.js +81 -0
  60. package/scripts/doc-counts.js +109 -0
  61. package/scripts/donate-qr.py +20 -0
  62. package/scripts/fake-node.js +534 -0
  63. package/scripts/index-bench.js +216 -0
  64. package/scripts/index-benchmark.js +117 -0
  65. package/scripts/index-build.js +40 -0
  66. package/scripts/live-render-check.mjs +89 -0
  67. package/scripts/manage-users.js +132 -0
  68. package/scripts/motion-check.mjs +138 -0
  69. package/scripts/pool-map.js +157 -0
  70. package/scripts/setup.js +410 -0
  71. package/scripts/shots.mjs +272 -0
  72. package/scripts/smoke.sh +327 -0
  73. package/scripts/ui.js +174 -0
  74. package/server/auth/sessions.js +221 -0
  75. package/server/auth/users.js +243 -0
  76. package/server/chain/blockfile.js +234 -0
  77. package/server/chain/index/build.js +193 -0
  78. package/server/chain/index/heights.js +36 -0
  79. package/server/chain/index/live.js +276 -0
  80. package/server/chain/index/rows.js +145 -0
  81. package/server/chain/index/store.js +154 -0
  82. package/server/chain/index/worker.js +109 -0
  83. package/server/chain/tx.js +310 -0
  84. package/server/collect/gbt.js +229 -0
  85. package/server/collect/logparse.js +765 -0
  86. package/server/collect/logtail.js +189 -0
  87. package/server/collect/markets.js +333 -0
  88. package/server/collect/mining.js +333 -0
  89. package/server/collect/monitor.js +2516 -0
  90. package/server/collect/nextblock.js +275 -0
  91. package/server/collect/sync.js +386 -0
  92. package/server/config.js +620 -0
  93. package/server/http/api.js +1275 -0
  94. package/server/http/explorer.js +418 -0
  95. package/server/http/server.js +412 -0
  96. package/server/http/sse.js +176 -0
  97. package/server/http/static.js +212 -0
  98. package/server/main.js +628 -0
  99. package/server/netinfo.js +253 -0
  100. package/server/rpc/allowlist.js +130 -0
  101. package/server/rpc/client.js +414 -0
  102. package/server/store/audit.js +148 -0
  103. package/server/store/history.js +220 -0
  104. package/server/store/ledger.js +290 -0
  105. package/server/store/ring.js +173 -0
  106. package/server/util/fmt.js +29 -0
  107. package/systemd/blockyard.service +100 -0
@@ -0,0 +1,188 @@
1
+ // THE PRICE CHART (operator, 2026-09-11, on the first Markets tab -- rows of towers on the 3D
2
+ // board with no axis at all: "What the fuck is this? Where is the price chart info?!??").
3
+ // A price chart has to be READ: a price axis, a time axis, candles, volume, the last price, and a
4
+ // crosshair that says exactly what an hour did. This is that chart. The 3D board under it is a
5
+ // view of the same hours, not a substitute for it.
6
+ import { niceTicks } from './charts.js';
7
+
8
+ export const EX_COLORS = { coinbase: '#4c8dff', kraken: '#a78bfa', bitstamp: '#2ecc8f', bitfinex: '#4dd0e1', okx: '#f0b429' };
9
+ const UP = '#26c281', DOWN = '#ef5350';
10
+ const UP_V = 'rgba(38,194,129,0.42)', DOWN_V = 'rgba(239,83,80,0.42)';
11
+ const PAD = { top: 28, right: 78, bottom: 22, left: 10 };
12
+ const MON = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
13
+ const H1 = 3600e3;
14
+
15
+ const money = (v, dp = 2) => (v == null || !Number.isFinite(v) ? '–' : v.toLocaleString('en-US', { minimumFractionDigits: dp, maximumFractionDigits: dp }));
16
+ const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
17
+ const stamp = (t) => { const d = new Date(t); return `${MON[d.getUTCMonth()]} ${d.getUTCDate()} ${String(d.getUTCHours()).padStart(2, '0')}:${String(d.getUTCMinutes()).padStart(2, '0')}`; };
18
+
19
+ // Pure: where everything goes. candles oldest first; overlays [{ candles }] only widen the scale.
20
+ export function layoutChart(candles, overlays, w, h) {
21
+ const n = candles.length;
22
+ const plotW = Math.max(10, w - PAD.left - PAD.right);
23
+ const plotH = Math.max(40, h - PAD.top - PAD.bottom);
24
+ const volH = Math.round(plotH * 0.2);
25
+ const priceH = plotH - volH - 8;
26
+ const t0 = candles[0]?.t ?? 0, t1 = candles.at(-1)?.t ?? 0;
27
+ let lo = Infinity, hi = -Infinity;
28
+ for (const k of candles) { lo = Math.min(lo, k.l ?? k.c); hi = Math.max(hi, k.h ?? k.c); }
29
+ for (const o of overlays ?? []) for (const k of o.candles) if (k.t >= t0 && k.t <= t1) { lo = Math.min(lo, k.c); hi = Math.max(hi, k.c); }
30
+ const padV = (hi - lo) * 0.06 || Math.abs(hi) * 0.001 || 1;
31
+ lo -= padV; hi += padV;
32
+ const vmax = Math.max(1e-9, ...candles.map((k) => k.v ?? 0));
33
+ const slot = plotW / Math.max(1, n);
34
+ const step = n > 1 ? (t1 - t0) / (n - 1) : H1;
35
+ const X = (i) => PAD.left + slot * (i + 0.5);
36
+ const XT = (t) => X((t - t0) / step);
37
+ const Y = (v) => PAD.top + priceH - ((v - lo) / (hi - lo)) * priceH;
38
+ const V = (y) => lo + (1 - (y - PAD.top) / priceH) * (hi - lo);
39
+ const VY0 = PAD.top + priceH + 8 + volH;
40
+ const VH = (v) => ((v ?? 0) / vmax) * volH;
41
+ const index = (x) => clamp(Math.round((x - PAD.left) / slot - 0.5), 0, Math.max(0, n - 1));
42
+ return { n, plotW, plotH, priceH, volH, lo, hi, slot, t0, t1, step, X, XT, Y, V, VY0, VH, index, w, h };
43
+ }
44
+
45
+ // Whole UTC hours, as far apart as the width can label (~80 px); midnight carries the date.
46
+ export function timeTicks(t0, t1, plotW) {
47
+ const span = Math.max(H1, t1 - t0);
48
+ const step = [1, 2, 3, 6, 12, 24, 48, 96].map((x) => x * H1).find((s) => plotW / (span / s) >= 80) ?? 96 * H1;
49
+ const out = [];
50
+ for (let t = Math.ceil(t0 / step) * step; t <= t1; t += step) {
51
+ const d = new Date(t);
52
+ out.push({ t, label: d.getUTCHours() === 0 ? `${MON[d.getUTCMonth()]} ${d.getUTCDate()}` : `${String(d.getUTCHours()).padStart(2, '0')}:00` });
53
+ }
54
+ return out;
55
+ }
56
+
57
+ export function readout(k, name) {
58
+ const ch = k.o ? (k.c - k.o) / k.o : null;
59
+ return `${name} · ${stamp(k.t)} UTC O ${money(k.o)} H ${money(k.h)} L ${money(k.l)} C ${money(k.c)} ${ch == null ? '' : `${ch >= 0 ? '+' : ''}${(ch * 100).toFixed(2)}%`} vol ${k.v == null ? '–' : money(k.v, 0)} BTC`;
60
+ }
61
+
62
+ export function prep(canvas) {
63
+ const dpr = Math.min(globalThis.devicePixelRatio || 1, 2);
64
+ const w = canvas.clientWidth || 800;
65
+ const h = canvas.clientHeight || 420;
66
+ if (canvas.width !== Math.round(w * dpr) || canvas.height !== Math.round(h * dpr)) {
67
+ canvas.width = Math.round(w * dpr);
68
+ canvas.height = Math.round(h * dpr);
69
+ }
70
+ const ctx = canvas.getContext('2d');
71
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
72
+ ctx.clearRect(0, 0, w, h);
73
+ ctx.font = '11px ui-monospace, SFMono-Regular, Menlo, monospace';
74
+ ctx.textBaseline = 'middle';
75
+ return { ctx, w, h };
76
+ }
77
+
78
+ export function drawPriceChart(canvas, { candles = [], overlays = [], name = '', hover = null } = {}) {
79
+ if (!canvas?.getContext) return null;
80
+ const { ctx, w, h } = prep(canvas);
81
+ if (!candles.length) {
82
+ ctx.fillStyle = '#6a7484'; ctx.textAlign = 'center';
83
+ ctx.fillText('no candles yet', w / 2, h / 2);
84
+ return null;
85
+ }
86
+ const L = layoutChart(candles, overlays, w, h);
87
+ const right = w - PAD.right;
88
+
89
+ // price grid and axis (right, as on a trading screen)
90
+ ctx.lineWidth = 1;
91
+ ctx.textAlign = 'left';
92
+ for (const v of niceTicks(L.lo, L.hi, Math.max(3, Math.floor(L.priceH / 46)))) {
93
+ const y = Math.round(L.Y(v)) + 0.5;
94
+ if (y < PAD.top || y > PAD.top + L.priceH) continue;
95
+ ctx.strokeStyle = '#1a2029';
96
+ ctx.beginPath(); ctx.moveTo(PAD.left, y); ctx.lineTo(right, y); ctx.stroke();
97
+ ctx.fillStyle = '#7d8898';
98
+ ctx.fillText(money(v, 0), right + 7, y);
99
+ }
100
+ // time grid and axis
101
+ ctx.textAlign = 'center';
102
+ for (const tk of timeTicks(L.t0, L.t1, L.plotW)) {
103
+ const x = Math.round(L.XT(tk.t)) + 0.5;
104
+ ctx.strokeStyle = tk.label.includes(' ') ? '#27303b' : '#161b22';
105
+ ctx.beginPath(); ctx.moveTo(x, PAD.top); ctx.lineTo(x, L.VY0); ctx.stroke();
106
+ ctx.fillStyle = tk.label.includes(' ') ? '#b5c0cc' : '#7d8898';
107
+ ctx.fillText(tk.label, x, h - PAD.bottom / 2);
108
+ }
109
+ // the pane edges
110
+ ctx.strokeStyle = '#2a323d';
111
+ ctx.beginPath(); ctx.moveTo(right + 0.5, PAD.top); ctx.lineTo(right + 0.5, L.VY0); ctx.stroke();
112
+ ctx.beginPath(); ctx.moveTo(PAD.left, L.VY0 + 0.5); ctx.lineTo(right, L.VY0 + 0.5); ctx.stroke();
113
+
114
+ const bodyW = Math.max(1, Math.min(16, L.slot * 0.66));
115
+ // volume
116
+ candles.forEach((k, i) => {
117
+ const vh = L.VH(k.v);
118
+ if (vh < 0.5) return;
119
+ ctx.fillStyle = k.c >= k.o ? UP_V : DOWN_V;
120
+ ctx.fillRect(L.X(i) - bodyW / 2, L.VY0 - vh, bodyW, vh);
121
+ });
122
+ ctx.fillStyle = '#56606e'; ctx.textAlign = 'left';
123
+ ctx.fillText('volume', PAD.left + 4, L.VY0 - L.volH + 6);
124
+
125
+ // the other exchanges, as thin close lines
126
+ for (const o of overlays) {
127
+ const pts = o.candles.filter((k) => k.t >= L.t0 && k.t <= L.t1);
128
+ if (pts.length < 2) continue;
129
+ ctx.strokeStyle = o.color; ctx.lineWidth = 1.1;
130
+ ctx.beginPath();
131
+ pts.forEach((k, j) => { const x = L.XT(k.t), y = L.Y(k.c); if (j) ctx.lineTo(x, y); else ctx.moveTo(x, y); });
132
+ ctx.stroke();
133
+ }
134
+ ctx.lineWidth = 1;
135
+
136
+ // candles: the wick is the hour's range, the body open to close
137
+ candles.forEach((k, i) => {
138
+ const x = Math.round(L.X(i)) + 0.5;
139
+ const col = k.c >= k.o ? UP : DOWN;
140
+ ctx.strokeStyle = col;
141
+ ctx.beginPath(); ctx.moveTo(x, L.Y(k.h ?? Math.max(k.o, k.c))); ctx.lineTo(x, L.Y(k.l ?? Math.min(k.o, k.c))); ctx.stroke();
142
+ const y1 = L.Y(Math.max(k.o, k.c)), y2 = L.Y(Math.min(k.o, k.c));
143
+ ctx.fillStyle = col;
144
+ ctx.fillRect(x - bodyW / 2, y1, bodyW, Math.max(1, y2 - y1));
145
+ });
146
+
147
+ // the last price: a dashed line and its label on the axis
148
+ const lastK = candles.at(-1);
149
+ const ly = Math.round(L.Y(lastK.c)) + 0.5;
150
+ const lcol = lastK.c >= lastK.o ? UP : DOWN;
151
+ ctx.strokeStyle = lcol; ctx.setLineDash([4, 3]);
152
+ ctx.beginPath(); ctx.moveTo(PAD.left, ly); ctx.lineTo(right, ly); ctx.stroke();
153
+ ctx.setLineDash([]);
154
+ ctx.fillStyle = lcol; ctx.fillRect(right + 1, ly - 9, PAD.right - 2, 18);
155
+ ctx.fillStyle = '#ffffff'; ctx.textAlign = 'left';
156
+ ctx.fillText(money(lastK.c), right + 6, ly);
157
+
158
+ // the crosshair
159
+ let shown = lastK;
160
+ if (hover && hover.x >= PAD.left && hover.x <= right) {
161
+ const i = L.index(hover.x);
162
+ shown = candles[i];
163
+ const x = Math.round(L.X(i)) + 0.5;
164
+ ctx.strokeStyle = 'rgba(200,215,230,0.45)'; ctx.setLineDash([3, 3]);
165
+ ctx.beginPath(); ctx.moveTo(x, PAD.top); ctx.lineTo(x, L.VY0); ctx.stroke();
166
+ if (hover.y >= PAD.top && hover.y <= PAD.top + L.priceH) {
167
+ const y = Math.round(hover.y) + 0.5;
168
+ ctx.beginPath(); ctx.moveTo(PAD.left, y); ctx.lineTo(right, y); ctx.stroke();
169
+ ctx.setLineDash([]);
170
+ ctx.fillStyle = '#3a4452'; ctx.fillRect(right + 1, y - 9, PAD.right - 2, 18);
171
+ ctx.fillStyle = '#ffffff'; ctx.fillText(money(L.V(hover.y)), right + 6, y);
172
+ }
173
+ ctx.setLineDash([]);
174
+ }
175
+ // readout (top-left) and overlay legend (top-right)
176
+ ctx.textAlign = 'left';
177
+ ctx.fillStyle = '#dfe6ee';
178
+ ctx.fillText(readout(shown, name), PAD.left + 2, 12);
179
+ ctx.textAlign = 'right';
180
+ let lx = right;
181
+ for (const o of [...overlays].reverse()) {
182
+ const wT = ctx.measureText(o.name).width;
183
+ ctx.fillStyle = '#9aa5b3'; ctx.fillText(o.name, lx, 12);
184
+ ctx.fillStyle = o.color; ctx.fillRect(lx - wT - 16, 11, 11, 2);
185
+ lx -= wT + 26;
186
+ }
187
+ return L;
188
+ }