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,29 @@
1
+ // Server-side formatting. Deliberately small: the browser has its own copy of
2
+ // the display rules (public/js/fmt.js) and the two must not drift in the
3
+ // one place that matters -- the ETA shape, which this project already prints as
4
+ // DD:HH:MM:SS in its own status line.
5
+
6
+ // DD:HH:MM:SS, as used by the node's downloader ETA and its heartbeat `uptime`.
7
+ export function formatEta(totalSeconds) {
8
+ if (totalSeconds == null || !Number.isFinite(totalSeconds) || totalSeconds < 0) return null;
9
+ const s = Math.floor(totalSeconds);
10
+ const d = Math.floor(s / 86400);
11
+ const h = Math.floor((s % 86400) / 3600);
12
+ const m = Math.floor((s % 3600) / 60);
13
+ const sec = s % 60;
14
+ return `${pad(d, 2)}:${pad(h, 2)}:${pad(m, 2)}:${pad(sec, 2)}`;
15
+ }
16
+
17
+ function pad(n, w) { return String(n).padStart(w, '0'); }
18
+
19
+ // Decimal units, matching how the node prints sizes ("4.0KB" for 4096 bytes).
20
+ const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
21
+ export function formatBytes(n, dp = 1) {
22
+ if (n == null || !Number.isFinite(n)) return 'n/a';
23
+ let v = Math.abs(n);
24
+ let i = 0;
25
+ while (v >= 1000 && i < UNITS.length - 1) { v /= 1000; i += 1; }
26
+ return `${(n < 0 ? '-' : '')}${v.toFixed(i === 0 ? 0 : dp)} ${UNITS[i]}`;
27
+ }
28
+
29
+
@@ -0,0 +1,100 @@
1
+ # BlockYard -- multi-user web monitor for a Bitcoin Core node.
2
+ #
3
+ # Install:
4
+ # sudo cp systemd/blockyard.service /etc/systemd/system/
5
+ # sudo systemctl daemon-reload && sudo systemctl enable --now blockyard
6
+ #
7
+ # Read-only by design: this unit needs no access to the node's datadir beyond the
8
+ # log file and the RPC cookie, and the app performs no node writes unless
9
+ # BLOCKYARD_ENABLE_ACTIONS=1 plus an explicit BLOCKYARD_ACTIONS list are set.
10
+ #
11
+ # Nothing in this file is machine- or person-specific on purpose: it is committed,
12
+ # so real usernames and host addresses belong in config/local.json, which is
13
+ # gitignored. Two lines below are therefore placeholders you must edit.
14
+ [Unit]
15
+ Description=BlockYard - Bitcoin node monitor
16
+ Documentation=file:///storage/blockyard/AGENTS.md
17
+ After=network-online.target
18
+ Wants=network-online.target
19
+ StartLimitIntervalSec=600
20
+ StartLimitBurst=5
21
+
22
+ [Service]
23
+ Type=simple
24
+ # EDIT ME: the account that may read <datadir>/<chain>/.cookie and the node log.
25
+ # Cookie authentication is unusable without that read access, so a wrong user here
26
+ # shows up as a permanently-offline node rather than a clear error.
27
+ User=blockyard
28
+ Group=blockyard
29
+ WorkingDirectory=/storage/blockyard
30
+ # Name the interpreter, do not go looking for it. Measured on this box 2026-09-09:
31
+ # /usr/bin/node is v18.19.1 -- below package.json engines ">=22", and it starts
32
+ # far enough to fail on syntax, which reads like a code bug.
33
+ # /usr/local/bin/node is a symlink into a root-owned private runtime; that home is
34
+ # mode 0700, so for any User= but root it does not exist -- and
35
+ # /usr/local/bin is FIRST on systemd's default PATH.
36
+ # `/usr/bin/env node` therefore resolves either to a runtime that is too old or to
37
+ # nothing. Pin PATH for child processes and give ExecStart an absolute path; generate
38
+ # the path once with `node -v` on the target and paste it in, since this file is
39
+ # committed and a per-machine interpreter belongs in a drop-in, not here.
40
+ #Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin
41
+ #ExecStart=/absolute/path/to/node server/main.js
42
+ ExecStart=/usr/bin/env node server/main.js
43
+ # always, not on-failure. The outage this box actually had -- service gone, nothing on
44
+ # the port, no error line anywhere in the log, no journal entry because nothing was
45
+ # supervising it -- is exactly the case on-failure cannot see: an exit 0, or a stop that
46
+ # leaves no trace. With Restart=always the exit status and signal at least reach the
47
+ # journal, which is the difference between "it died" and "it died of 9/KILL at 08:35".
48
+ Restart=always
49
+ RestartSec=10
50
+ KillSignal=SIGTERM
51
+ # SIGTERM triggers the durable-shutdown path (history + sessions are saved with
52
+ # tmp+fsync+rename), so give it room to finish rather than SIGKILL mid-flush.
53
+ TimeoutStopSec=45
54
+
55
+ # BINDING. Which address to serve is a per-machine decision, so it lives in
56
+ # config/local.json (`server.hosts`), not here -- that file is gitignored and the
57
+ # app refuses to start if a configured address is absent at boot, rather than
58
+ # silently falling back to a wildcard. A previous revision of this file embedded a
59
+ # real LAN address here AND had two Environment= assignments concatenated onto one
60
+ # line, which silently discarded BLOCKYARD_PORT; both are fixed by not putting
61
+ # machine facts in a committed file in the first place.
62
+ #
63
+ # Consequences worth remembering: binding a single non-loopback address means
64
+ # 127.0.0.1 on the host itself stops working (curl checks must use that address),
65
+ # and clients that reach the box over a tunnel need that tunnel's address listed.
66
+ Environment=BLOCKYARD_PORT=21000
67
+ Environment=BLOCKYARD_NODE_URL=http://127.0.0.1:8331
68
+ Environment=BLOCKYARD_DATADIR=/home/bitcoin/.bitcoin
69
+ Environment=BLOCKYARD_LOGFILE=/home/bitcoin/.bitcoin/debug.log
70
+ Environment=BLOCKYARD_LOG_LEVEL=info
71
+ # ACCESS: accounts are OFF by default, so anyone who can reach the bound addresses
72
+ # reads this monitor (role "viewer": charts, feeds, read-only RPC console). User
73
+ # administration, the audit trail and node writes stay closed to them. Uncomment to
74
+ # require sign-in (accounts, roles, sessions, CSRF, per-user audit):
75
+ #Environment=BLOCKYARD_AUTH=1
76
+ #
77
+ # Node writes stay off, and while accounts are off they stay off even if actions are
78
+ # enabled -- a write with no identity behind it is not attributable. Enabling needs
79
+ # ALL of: the two lines below, accounts on (above), or the explicit
80
+ # BLOCKYARD_ALLOW_WRITES_WITHOUT_AUTH=1. The second line names the specific actions, so
81
+ # "we turned on writes" is never an unspecific statement.
82
+ #Environment=BLOCKYARD_ENABLE_ACTIONS=1
83
+ #Environment=BLOCKYARD_ACTIONS=testmempoolaccept,savemempool
84
+
85
+ # Modest hardening. NoNewPrivileges plus a read-only /home is enough here: the
86
+ # service must read the node's RPC cookie and log, so a full PrivateTmp/
87
+ # ProtectSystem=strict would fight the thing it is monitoring.
88
+ NoNewPrivileges=true
89
+ ProtectKernelTunables=true
90
+ ProtectKernelModules=true
91
+ ProtectControlGroups=true
92
+ RestrictSUIDSGID=true
93
+ LockPersonality=true
94
+
95
+ StandardOutput=journal
96
+ StandardError=journal
97
+ SyslogIdentifier=blockyard
98
+
99
+ [Install]
100
+ WantedBy=multi-user.target