chore: release v1.7.49-alpha
This commit is contained in:
@@ -606,7 +606,8 @@
|
||||
console.log('[Bitcoin UI] Script loaded, initializing...');
|
||||
|
||||
// RPC Configuration - Use local Nginx proxy within container
|
||||
const RPC_ENDPOINT = '/bitcoin-rpc/';
|
||||
const RPC_ENDPOINT = 'bitcoin-rpc/';
|
||||
const STATUS_ENDPOINT = 'bitcoin-status';
|
||||
console.log('[Bitcoin UI] RPC Endpoint:', RPC_ENDPOINT);
|
||||
|
||||
// Make RPC call to Bitcoin node via local proxy
|
||||
@@ -645,6 +646,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchBitcoinStatus() {
|
||||
const response = await fetch(STATUS_ENDPOINT, { cache: 'no-store' });
|
||||
if (!response.ok) {
|
||||
throw new Error(`status HTTP ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Implementation branding — detected from getnetworkinfo.subversion.
|
||||
// Bitcoin Knots identifies as "/Satoshi:<ver>/Knots:<date>/", Bitcoin Core as "/Satoshi:<ver>/".
|
||||
let brandingApplied = false;
|
||||
@@ -672,22 +681,62 @@
|
||||
|
||||
// Track last block count for animations
|
||||
let lastBlockCount = 0;
|
||||
let consecutiveRpcFailures = 0;
|
||||
let lastSuccessfulUpdateAt = 0;
|
||||
|
||||
function formatPercent(value) {
|
||||
if (!Number.isFinite(value) || value <= 0) return '0.00';
|
||||
if (value < 0.01) return '<0.01';
|
||||
return value.toFixed(2);
|
||||
}
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (!Number.isFinite(bytes) || bytes <= 0) return null;
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let value = bytes;
|
||||
let unit = 0;
|
||||
while (value >= 1000 && unit < units.length - 1) {
|
||||
value /= 1000;
|
||||
unit += 1;
|
||||
}
|
||||
return `${value.toFixed(unit >= 3 ? 1 : 0)} ${units[unit]}`;
|
||||
}
|
||||
|
||||
// Update blockchain info
|
||||
async function updateBlockchainInfo() {
|
||||
console.log('[Bitcoin UI] updateBlockchainInfo() called');
|
||||
try {
|
||||
const blockchainInfo = await callRPC('getblockchaininfo');
|
||||
const status = await fetchBitcoinStatus();
|
||||
const blockchainInfo = status.blockchain_info;
|
||||
console.log('[Bitcoin UI] blockchainInfo:', blockchainInfo);
|
||||
|
||||
if (!blockchainInfo) {
|
||||
console.error('[Bitcoin UI] No blockchain info received');
|
||||
document.getElementById('syncStatusText').textContent = 'Unable to connect to Bitcoin node';
|
||||
document.getElementById('syncStatusText').className = 'text-red-400 text-sm';
|
||||
consecutiveRpcFailures += 1;
|
||||
const syncStatusText = document.getElementById('syncStatusText');
|
||||
const syncIcon = document.getElementById('syncIcon');
|
||||
if (syncStatusText) {
|
||||
if (status.stale) {
|
||||
syncStatusText.textContent = status.error || 'Bitcoin node is reconnecting... showing last known values';
|
||||
syncStatusText.className = 'text-yellow-300 text-sm font-medium';
|
||||
} else if (consecutiveRpcFailures < 6) {
|
||||
syncStatusText.textContent = status.error || 'Connecting to Bitcoin node...';
|
||||
syncStatusText.className = 'text-yellow-300 text-sm font-medium';
|
||||
} else {
|
||||
syncStatusText.textContent = status.error || 'Bitcoin node is not responding yet';
|
||||
syncStatusText.className = 'text-red-400 text-sm font-medium';
|
||||
}
|
||||
}
|
||||
if (syncIcon) {
|
||||
syncIcon.classList.add('animate-spin-slow');
|
||||
syncIcon.classList.remove('text-green-500');
|
||||
}
|
||||
return;
|
||||
}
|
||||
consecutiveRpcFailures = 0;
|
||||
lastSuccessfulUpdateAt = Date.now();
|
||||
|
||||
const networkInfo = await callRPC('getnetworkinfo');
|
||||
const networkInfo = status.network_info;
|
||||
|
||||
applyImplBranding(networkInfo && networkInfo.subversion);
|
||||
|
||||
@@ -743,44 +792,51 @@
|
||||
}
|
||||
|
||||
// Populate Settings — Transaction Index, ZMQ, RPC (fire-and-forget)
|
||||
(async () => {
|
||||
const txIndexEl = document.getElementById('settingsTxIndex');
|
||||
if (txIndexEl) {
|
||||
const idx = await callRPC('getindexinfo');
|
||||
if (idx && typeof idx === 'object') {
|
||||
const names = Object.keys(idx);
|
||||
txIndexEl.textContent = names.length
|
||||
? `Enabled: ${names.join(', ')}`
|
||||
: 'Disabled';
|
||||
} else {
|
||||
txIndexEl.textContent = 'Disabled';
|
||||
}
|
||||
const txIndexEl = document.getElementById('settingsTxIndex');
|
||||
if (txIndexEl) {
|
||||
const idx = status.index_info;
|
||||
if (idx && typeof idx === 'object') {
|
||||
const names = Object.keys(idx);
|
||||
txIndexEl.textContent = names.length
|
||||
? `Enabled: ${names.join(', ')}`
|
||||
: 'Disabled';
|
||||
} else {
|
||||
txIndexEl.textContent = 'Unavailable while node starts';
|
||||
}
|
||||
const zmqEl = document.getElementById('settingsZmq');
|
||||
if (zmqEl) {
|
||||
const zmq = await callRPC('getzmqnotifications');
|
||||
if (Array.isArray(zmq) && zmq.length) {
|
||||
zmqEl.textContent = zmq.map(z => `${z.type}@${z.address}`).join('; ');
|
||||
} else {
|
||||
zmqEl.textContent = 'Not enabled';
|
||||
}
|
||||
}
|
||||
const zmqEl = document.getElementById('settingsZmq');
|
||||
if (zmqEl) {
|
||||
const zmq = status.zmq_notifications;
|
||||
if (Array.isArray(zmq) && zmq.length) {
|
||||
zmqEl.textContent = zmq.map(z => `${z.type}@${z.address}`).join('; ');
|
||||
} else if (Array.isArray(zmq)) {
|
||||
zmqEl.textContent = 'Not enabled';
|
||||
} else {
|
||||
zmqEl.textContent = 'Unavailable while node starts';
|
||||
}
|
||||
const rpcEl = document.getElementById('settingsRpc');
|
||||
if (rpcEl && networkInfo) {
|
||||
const port = chain === 'main' ? 8332 : (chain === 'test' ? 18332 : (chain === 'signet' ? 38332 : 18443));
|
||||
rpcEl.textContent = `Reachable on port ${port}`;
|
||||
}
|
||||
})();
|
||||
}
|
||||
const rpcEl = document.getElementById('settingsRpc');
|
||||
if (rpcEl) {
|
||||
const port = chain === 'main' ? 8332 : (chain === 'test' ? 18332 : (chain === 'signet' ? 38332 : 18443));
|
||||
rpcEl.textContent = status.stale
|
||||
? `Reconnecting on port ${port}`
|
||||
: `Reachable on port ${port}`;
|
||||
}
|
||||
|
||||
// Update sync status
|
||||
const blocks = blockchainInfo.blocks || 0;
|
||||
const headers = blockchainInfo.headers || 0;
|
||||
const verificationProgress = blockchainInfo.verificationprogress || 0;
|
||||
const isSynced = blocks >= headers - 1;
|
||||
const initialBlockDownload = blockchainInfo.initialblockdownload === true;
|
||||
const isSynced = headers > 0 && blocks >= headers - 1 && !initialBlockDownload;
|
||||
const diskSize = formatBytes(blockchainInfo.size_on_disk || 0);
|
||||
const appearsToBeReindexing = initialBlockDownload && blocks === 0 && headers > 0 && (blockchainInfo.size_on_disk || 0) > 1024 * 1024 * 1024;
|
||||
|
||||
// Calculate actual sync percentage based on blocks/headers
|
||||
const actualSyncPercentage = headers > 0 ? ((blocks / headers) * 100).toFixed(2) : '0.00';
|
||||
const verificationPercentage = (verificationProgress * 100).toFixed(2);
|
||||
const actualSyncValue = headers > 0 ? (blocks / headers) * 100 : 0;
|
||||
const actualSyncPercentage = formatPercent(actualSyncValue);
|
||||
const progressWidth = Math.max(0, Math.min(100, actualSyncValue));
|
||||
const verificationPercentage = formatPercent(verificationProgress * 100);
|
||||
|
||||
// Animate block count if it changed
|
||||
const currentHeightElem = document.getElementById('currentHeight');
|
||||
@@ -795,16 +851,27 @@
|
||||
document.getElementById('headers').textContent = headers.toLocaleString();
|
||||
document.getElementById('verificationProgress').textContent = `${verificationPercentage}%`;
|
||||
document.getElementById('syncPercentage').textContent = `${actualSyncPercentage}%`;
|
||||
document.getElementById('currentBlock').textContent = `Block ${blocks.toLocaleString()}`;
|
||||
document.getElementById('syncProgressBar').style.width = `${actualSyncPercentage}%`;
|
||||
document.getElementById('currentBlock').textContent = appearsToBeReindexing
|
||||
? 'Reindexing from disk'
|
||||
: `Block ${blocks.toLocaleString()}`;
|
||||
document.getElementById('syncProgressBar').style.width = `${progressWidth}%`;
|
||||
|
||||
// Update sync status text and icon
|
||||
const syncStatusText = document.getElementById('syncStatusText');
|
||||
const syncIcon = document.getElementById('syncIcon');
|
||||
|
||||
if (isSynced) {
|
||||
syncStatusText.textContent = '✓ Fully synchronized with the network';
|
||||
syncStatusText.className = 'text-green-400 text-sm font-medium';
|
||||
if (appearsToBeReindexing) {
|
||||
syncStatusText.textContent = `Reindexing local block files${diskSize ? ` (${diskSize} on disk)` : ''}`;
|
||||
syncStatusText.className = 'text-orange-400 text-sm font-medium';
|
||||
if (syncIcon) {
|
||||
syncIcon.classList.add('animate-spin-slow');
|
||||
syncIcon.classList.remove('text-green-500');
|
||||
}
|
||||
} else if (isSynced) {
|
||||
syncStatusText.textContent = status.stale
|
||||
? 'Bitcoin node is reconnecting... showing last known synchronized state'
|
||||
: '✓ Fully synchronized with the network';
|
||||
syncStatusText.className = status.stale ? 'text-yellow-300 text-sm font-medium' : 'text-green-400 text-sm font-medium';
|
||||
// Stop spinning when synced
|
||||
if (syncIcon) {
|
||||
syncIcon.classList.remove('animate-spin-slow');
|
||||
@@ -812,8 +879,12 @@
|
||||
}
|
||||
} else {
|
||||
const remaining = headers - blocks;
|
||||
syncStatusText.textContent = `Syncing... ${remaining.toLocaleString()} blocks remaining`;
|
||||
syncStatusText.className = 'text-orange-400 text-sm font-medium';
|
||||
syncStatusText.textContent = status.stale
|
||||
? 'Bitcoin node is reconnecting... showing last known sync state'
|
||||
: initialBlockDownload
|
||||
? `Initial block download... ${remaining.toLocaleString()} blocks remaining`
|
||||
: `Syncing... ${remaining.toLocaleString()} blocks remaining`;
|
||||
syncStatusText.className = status.stale ? 'text-yellow-300 text-sm font-medium' : 'text-orange-400 text-sm font-medium';
|
||||
// Keep spinning while syncing
|
||||
if (syncIcon) {
|
||||
syncIcon.classList.add('animate-spin-slow');
|
||||
@@ -834,8 +905,15 @@
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to update blockchain info:', error);
|
||||
document.getElementById('syncStatusText').textContent = 'Unable to fetch blockchain data';
|
||||
document.getElementById('syncStatusText').className = 'text-red-400 text-sm';
|
||||
consecutiveRpcFailures += 1;
|
||||
const syncStatusText = document.getElementById('syncStatusText');
|
||||
if (syncStatusText) {
|
||||
const hasRecentData = lastSuccessfulUpdateAt > 0 && Date.now() - lastSuccessfulUpdateAt < 120000;
|
||||
syncStatusText.textContent = hasRecentData
|
||||
? 'Bitcoin status bridge is reconnecting... keeping last known values'
|
||||
: 'Connecting to Bitcoin status bridge...';
|
||||
syncStatusText.className = 'text-yellow-300 text-sm font-medium';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user