Update server/addresses.js

Add Fulcrum address data queries
This commit is contained in:
2026-08-29 10:50:03 +00:00
parent 6e36b3d16d
commit 79d37f5dd3
+228
View File
@@ -1,7 +1,9 @@
const crypto = require('crypto') const crypto = require('crypto')
const fs = require('fs/promises') const fs = require('fs/promises')
const net = require('net')
const storePath = '/data/store.json' const storePath = '/data/store.json'
const fulcrumTimeoutMs = 3000
async function readStore() { async function readStore() {
try { try {
@@ -122,8 +124,234 @@ async function removeAddress(address) {
return true return true
} }
function queryFulcrum(fulcrumUrl, method, params = []) {
return new Promise((resolve) => {
if (!fulcrumUrl) {
resolve({
ok: false,
result: null,
error: 'Fulcrum URL is not configured',
})
return
}
let parsed
try {
parsed = new URL(fulcrumUrl)
} catch {
resolve({
ok: false,
result: null,
error: 'Invalid Fulcrum URL',
})
return
}
if (parsed.protocol !== 'tcp:') {
resolve({
ok: false,
result: null,
error: 'Fulcrum URL must use tcp://',
})
return
}
const host = parsed.hostname
const port = Number(parsed.port)
if (!host || !port) {
resolve({
ok: false,
result: null,
error: 'Fulcrum URL is missing host or port',
})
return
}
const socket = net.createConnection({
host,
port,
})
let response = ''
let settled = false
const finish = (value) => {
if (settled) {
return
}
settled = true
socket.destroy()
resolve(value)
}
socket.setTimeout(fulcrumTimeoutMs)
socket.on('connect', () => {
const request = JSON.stringify({
jsonrpc: '2.0',
id: 1,
method,
params,
}) + '\n'
socket.write(request)
})
socket.on('data', (data) => {
response += data.toString()
const lines = response.split('\n')
for (const line of lines) {
if (!line.trim()) {
continue
}
let message
try {
message = JSON.parse(line)
} catch {
continue
}
if (message.error) {
finish({
ok: false,
result: null,
error: message.error,
})
return
}
if (
Object.prototype.hasOwnProperty.call(
message,
'result',
)
) {
finish({
ok: true,
result: message.result,
error: null,
})
return
}
}
})
socket.on('timeout', () => {
finish({
ok: false,
result: null,
error: 'Connection timed out',
})
})
socket.on('error', (error) => {
finish({
ok: false,
result: null,
error: error.message,
})
})
socket.on('close', () => {
finish({
ok: false,
result: null,
error: 'Connection closed before a response was received',
})
})
})
}
async function getAddressData(address) {
const fulcrumUrl = process.env.MUNIN_FULCRUM_URL || null
if (!fulcrumUrl) {
throw new Error('Fulcrum URL is not configured')
}
const history = await queryFulcrum(
fulcrumUrl,
'blockchain.address.get_history',
[address],
)
if (!history.ok) {
throw new Error(
`Failed to query address history: ${JSON.stringify(history.error)}`,
)
}
const utxos = await queryFulcrum(
fulcrumUrl,
'blockchain.address.listunspent',
[address],
)
if (!utxos.ok) {
throw new Error(
`Failed to query address UTXOs: ${JSON.stringify(utxos.error)}`,
)
}
const confirmedBalance = utxos.result.reduce(
(total, item) => total + Number(item.value || 0),
0,
)
return {
address,
confirmedBalance,
unconfirmedBalance: 0,
utxos: utxos.result,
history: history.result,
}
}
async function getAddressesWithData() {
const addresses = await listAddresses()
const results = []
for (const entry of addresses) {
try {
const data = await getAddressData(entry.address)
results.push({
...entry,
confirmedBalance: data.confirmedBalance,
unconfirmedBalance: data.unconfirmedBalance,
utxos: data.utxos,
history: data.history,
error: null,
})
} catch (error) {
results.push({
...entry,
confirmedBalance: null,
unconfirmedBalance: null,
utxos: [],
history: [],
error: error.message,
})
}
}
return results
}
module.exports = { module.exports = {
listAddresses, listAddresses,
addAddress, addAddress,
removeAddress, removeAddress,
getAddressData,
getAddressesWithData,
} }