UNPKG

wallet-storage

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

189 lines 8.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.purgeData = purgeData; const sdk_1 = require("@bsv/sdk"); const index_client_1 = require("../../index.client"); async function purgeData(storage, params, trx) { const r = { count: 0, log: '' }; const defaultAge = 1000 * 60 * 60 * 24 * 14; const runPurgeQuery = async (pq) => { try { pq.sql = pq.q.toString(); const count = await pq.q; if (count > 0) { r.count += count; r.log += `${count} ${pq.log}\n`; } } catch (eu) { // eslint-disable-next-line @typescript-eslint/no-unused-vars const e = index_client_1.sdk.WalletError.fromUnknown(eu); throw eu; } }; if (params.purgeCompleted) { const age = params.purgeCompletedAge || defaultAge; const before = toSqlWhereDate(new Date(Date.now() - age)); // eslint-disable-next-line @typescript-eslint/no-explicit-any const qs = []; // select * from transactions where updated_at < '2024-08-20' and status = 'completed' and not provenTxId is null and (not truncatedExternalInputs is null or not beef is null or not rawTx is null) qs.push({ log: 'conpleted transactions purged of transient data', q: storage.toDb(trx)('transactions') .update({ inputBEEF: null, rawTx: null }) .where('updated_at', '<', before) .where('status', 'completed') .whereNotNull('provenTxId') .where(function () { this.orWhereNotNull('inputBEEF'); this.orWhereNotNull('rawTx'); }) }); const completedReqs = await storage.toDb(trx)('proven_tx_reqs') .select("provenTxReqId") .where('updated_at', '<', before) .where('status', 'completed') .whereNotNull('provenTxId') .where('notified', 1); const completedReqIds = completedReqs.map(o => o.provenTxReqId); if (completedReqIds.length > 0) { qs.push({ log: 'completed proven_tx_reqs deleted', q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', completedReqIds).delete() }); } for (const q of qs) await runPurgeQuery(q); } if (params.purgeFailed) { const age = params.purgeFailedAge || defaultAge; const before = toSqlWhereDate(new Date(Date.now() - age)); const qs = []; const failedTxsQ = storage.toDb(trx)('transactions') .select("transactionId") .where('updated_at', '<', before) .where('status', 'failed'); const txs = await failedTxsQ; const failedTxIds = txs.map(tx => tx.transactionId); await deleteTransactions(failedTxIds, qs, 'failed', true); const invalidReqs = await storage.toDb(trx)('proven_tx_reqs') .select("provenTxReqId") .where('updated_at', '<', before) .where('status', 'invalid'); const invalidReqIds = invalidReqs.map(o => o.provenTxReqId); if (invalidReqIds.length > 0) qs.push({ log: 'invalid proven_tx_reqs deleted', q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', invalidReqIds).delete() }); const doubleSpendReqs = await storage.toDb(trx)('proven_tx_reqs') .select("provenTxReqId") .where('updated_at', '<', before) .where('status', 'doubleSpend'); const doubleSpendReqIds = doubleSpendReqs.map(o => o.provenTxReqId); if (doubleSpendReqIds.length > 0) qs.push({ log: 'doubleSpend proven_tx_reqs deleted', q: storage.toDb(trx)('proven_tx_reqs').whereIn('provenTxReqId', doubleSpendReqIds).delete() }); for (const q of qs) await runPurgeQuery(q); } if (params.purgeSpent) { const age = params.purgeSpentAge || defaultAge; const before = toSqlWhereDate(new Date(Date.now() - age)); const beef = new sdk_1.Beef(); const utxos = await storage.findOutputs({ partial: { spendable: true }, txStatus: ['sending', 'unproven', 'completed', 'nosend'] }); for (const utxo of utxos) { // Figure out all the txids required to prove the validity of this utxo and merge proofs into beef. const options = { mergeToBeef: beef, ignoreServices: true }; if (utxo.txid) await storage.getBeefForTransaction(utxo.txid, options); } const proofTxids = {}; for (const btx of beef.txs) proofTxids[btx.txid] = true; let qs = []; const spentTxsQ = storage.toDb(trx)('transactions') .where('updated_at', '<', before) .where('status', 'completed') .whereRaw(`not exists(select outputId from outputs as o where o.transactionId = transactions.transactionId and o.spendable = 1)`); const txs = await spentTxsQ; // Save any spent txid still needed to prove a utxo: const nptxs = txs.filter(t => !proofTxids[t.txid || '']); let spentTxIds = nptxs.map(tx => tx.transactionId); if (spentTxIds.length > 0) { const update = { spentBy: undefined }; qs.push({ log: 'spent outputs no longer tracked by spentBy', q: storage.toDb(trx)('outputs').update(storage.validatePartialForUpdate(update, undefined, ['spendable'])) .where('spendable', false) .whereIn('spentBy', spentTxIds) }); await deleteTransactions(spentTxIds, qs, 'spent', false); for (const q of qs) await runPurgeQuery(q); } } // Delete proven_txs no longer referenced by remaining transactions. const qs = []; qs.push({ log: 'orphan proven_txs deleted', q: storage.toDb(trx)('proven_txs') .whereRaw(`not exists(select * from transactions as t where t.txid = proven_txs.txid or t.provenTxId = proven_txs.provenTxId)`) .whereRaw(`not exists(select * from proven_tx_reqs as r where r.txid = proven_txs.txid or r.provenTxId = proven_txs.provenTxId)`) .delete() }); for (const q of qs) await runPurgeQuery(q); return r; async function deleteTransactions(transactionIds, qs, reason, markNotSpentBy) { if (transactionIds.length > 0) { const outputs = await storage.toDb(trx)('outputs') .select("outputId") .whereIn('transactionId', transactionIds); const outputIds = outputs.map(o => o.outputId); if (outputIds.length > 0) { qs.push({ log: `${reason} output_tags_map deleted`, q: storage.toDb(trx)('output_tags_map').whereIn("outputId", outputIds).delete() }); qs.push({ log: `${reason} outputs deleted`, q: storage.toDb(trx)('outputs').whereIn("outputId", outputIds).delete() }); } qs.push({ log: `${reason} tx_labels_map deleted`, q: storage.toDb(trx)('tx_labels_map').whereIn("transactionId", transactionIds).delete() }); qs.push({ log: `${reason} commissions deleted`, q: storage.toDb(trx)('commissions').whereIn('transactionId', transactionIds).delete() }); if (markNotSpentBy) { qs.push({ log: 'unspent outputs updated to spendable', q: storage.toDb(trx)('outputs').update({ spendable: true, spentBy: undefined }).whereIn('spentBy', transactionIds) }); } qs.push({ log: `${reason} transactions deleted`, q: storage.toDb(trx)('transactions').whereIn('transactionId', transactionIds).delete() }); } } } function toSqlWhereDate(d) { let s = d.toISOString(); s = s.replace('T', ' '); s = s.replace('Z', ''); return s; } //# sourceMappingURL=purgeData.js.map