UNPKG

@bsv/wallet-toolbox-client

Version:
144 lines 5.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TaskUnFail = void 0; const sdk_1 = require("@bsv/sdk"); const WalletMonitorTask_1 = require("./WalletMonitorTask"); const entities_1 = require("../../storage/schema/entities"); /** * Setting provenTxReq status to 'unfail' when 'invalid' will attempt to find a merklePath, and if successful: * * 1. set the req status to 'unmined' * 2. set the referenced txs to 'unproven' * 3. determine if any inputs match user's existing outputs and if so update spentBy and spendable of those outputs. * 4. set the txs outputs to spendable * * If it fails (to find a merklePath), returns the req status to 'invalid'. */ class TaskUnFail extends WalletMonitorTask_1.WalletMonitorTask { constructor(monitor, triggerMsecs = monitor.oneMinute * 10) { super(monitor, TaskUnFail.taskName); this.triggerMsecs = triggerMsecs; } trigger(nowMsecsSinceEpoch) { return { run: TaskUnFail.checkNow || (this.triggerMsecs > 0 && nowMsecsSinceEpoch - this.lastRunMsecsSinceEpoch > this.triggerMsecs) }; } async runTask() { let log = ''; TaskUnFail.checkNow = false; const limit = 100; let offset = 0; for (;;) { const reqs = await this.storage.findProvenTxReqs({ partial: {}, status: ['unfail'], paged: { limit, offset } }); if (reqs.length === 0) break; log += `${reqs.length} reqs with status 'unfail'\n`; const r = await this.unfail(reqs, 2); log += `${r.log}\n`; //console.log(log); if (reqs.length < limit) break; offset += limit; } return log; } async unfail(reqs, indent = 0) { let log = ''; for (const reqApi of reqs) { const req = new entities_1.EntityProvenTxReq(reqApi); log += ' '.repeat(indent); log += `reqId ${reqApi.provenTxReqId} txid ${reqApi.txid}: `; const r = await this.monitor.services.getMerklePath(req.txid); if (r.merklePath) { // 1. set the req status to 'unmined' req.status = 'unmined'; req.attempts = 0; log += `unfailed. status is now 'unmined'\n`; log += await this.unfailReq(req, indent + 2); } else { req.status = 'invalid'; log += `returned to status 'invalid'\n`; } await req.updateStorageDynamicProperties(this.storage); } return { log }; } /** * 2. set the referenced txs to 'unproven' * 3. determine if any inputs match user's existing outputs and if so update spentBy and spendable of those outputs. * 4. set the txs outputs to spendable * * @param req * @param indent * @returns */ async unfailReq(req, indent) { let log = ''; const storage = this.storage; const services = this.monitor.services; const txIds = req.notify.transactionIds || []; for (const id of txIds) { const bsvtx = sdk_1.Transaction.fromBinary(req.rawTx); await this.storage.runAsStorageProvider(async (sp) => { const spk = sp; const tx = await sp.findTransactionById(id, undefined, true); if (!tx) { log += ' '.repeat(indent) + `transaction ${id} was not found\n`; return; } await sp.updateTransaction(tx.transactionId, { status: 'unproven' }); tx.status = 'unproven'; log += ' '.repeat(indent) + `transaction ${id} status is now 'unproven'\n`; let vin = -1; for (const bi of bsvtx.inputs) { vin++; const is = await sp.findOutputs({ partial: { userId: tx.userId, txid: bi.sourceTXID, vout: bi.sourceOutputIndex } }); if (is.length !== 1) { log += ' '.repeat(indent + 2) + `input ${vin} not matched to user's outputs\n`; } else { const oi = is[0]; log += ' '.repeat(indent + 2) + `input ${vin} matched to output ${oi.outputId} updated spentBy ${tx.transactionId}\n`; await sp.updateOutput(oi.outputId, { spendable: false, spentBy: tx.transactionId }); } } const outputs = await sp.findOutputs({ partial: { userId: tx.userId, transactionId: tx.transactionId } }); for (const o of outputs) { await spk.validateOutputScript(o); if (!o.lockingScript) { log += ' '.repeat(indent + 2) + `output ${o.outputId} does not have a valid locking script\n`; } else { const isUtxo = await services.isUtxo(o); if (isUtxo !== o.spendable) { log += ' '.repeat(indent + 2) + `output ${o.outputId} set to ${isUtxo ? 'spendable' : 'spent'}\n`; await sp.updateOutput(o.outputId, { spendable: isUtxo }); } else { log += ' '.repeat(indent + 2) + `output ${o.outputId} unchanged\n`; } } } }); } return log; } } exports.TaskUnFail = TaskUnFail; TaskUnFail.taskName = 'UnFail'; /** * Set to true to trigger running this task */ TaskUnFail.checkNow = false; //# sourceMappingURL=TaskUnFail.js.map