UNPKG

wallet-storage

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

593 lines 25.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StorageMySQLDojoReader = void 0; const sdk_1 = require("@bsv/sdk"); const index_all_1 = require("../../index.all"); const index_all_2 = require("../index.all"); const sdk_2 = require("../../sdk"); const StorageReader_1 = require("../StorageReader"); class StorageMySQLDojoReader extends StorageReader_1.StorageReader { constructor(options) { super(options); if (!options.knex) throw new index_all_1.sdk.WERR_INVALID_PARAMETER('options.knex', `valid`); this.knex = options.knex; } async destroy() { var _a; await ((_a = this.knex) === null || _a === void 0 ? void 0 : _a.destroy()); } async transaction(scope, trx) { if (trx) return await scope(trx); return await this.knex.transaction(async (knextrx) => { const trx = knextrx; return await scope(trx); }); } toDb(trx) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const db = !trx ? this.knex : trx; this.whenLastAccess = new Date(); return db; } async readSettings(trx) { const d = (0, index_all_1.verifyOne)(await this.toDb(trx)('settings')); const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), storageIdentityKey: (0, index_all_1.verifyHexString)(d.dojoIdentityKey), storageName: d.dojoName || `${this.chain} Legacy Import`, chain: this.chain, dbtype: "MySQL", maxOutputScript: 256 }; if (r.storageName.startsWith('staging') && this.chain !== 'test') throw new index_all_1.sdk.WERR_INVALID_PARAMETER('chain', `in aggreement with storage chain ${r.storageName}`); this._settings = r; return r; } setupQuery(table, args) { let q = this.toDb(args.trx)(table); if (args.partial && Object.keys(args.partial).length > 0) q.where(args.partial); if (args.since) q.where('updated_at', '>=', this.validateDateForWhere(args.since)); if (args.paged) { q.limit(args.paged.limit); q.offset(args.paged.offset || 0); } return q; } findOutputBasketsQuery(args) { return this.setupQuery('output_baskets', args); } async findOutputBaskets(args) { const q = this.findOutputBasketsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), basketId: (0, index_all_1.verifyInteger)(d.basketId), userId: (0, index_all_1.verifyInteger)(d.userId), name: (0, index_all_1.verifyTruthy)(d.name).trim().toLowerCase(), numberOfDesiredUTXOs: (0, index_all_1.verifyInteger)(d.numberOfDesiredUTXOs), minimumDesiredUTXOValue: (0, index_all_1.verifyInteger)(d.minimumDesiredUTXOValue), isDeleted: !!d.isDeleted }; rs.push(r); } return this.validateEntities(rs, undefined, ['isDeleted']); } findTxLabelsQuery(args) { return this.setupQuery('tx_labels', args); } async findTxLabels(args) { const q = this.findTxLabelsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), txLabelId: (0, index_all_1.verifyInteger)(d.txLabelId), userId: (0, index_all_1.verifyInteger)(d.userId), label: (0, index_all_1.verifyTruthy)(d.label).trim().toLowerCase(), isDeleted: !!d.isDeleted }; rs.push(r); } return this.validateEntities(rs, undefined, ['isDeleted']); } findOutputTagsQuery(args) { return this.setupQuery('output_tags', args); } async findOutputTags(args) { const q = this.findOutputTagsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), outputTagId: (0, index_all_1.verifyInteger)(d.outputTagId), userId: (0, index_all_1.verifyInteger)(d.userId), tag: (0, index_all_1.verifyTruthy)(d.tag).trim().toLowerCase(), isDeleted: !!d.isDeleted }; rs.push(r); } return this.validateEntities(rs, undefined, ['isDeleted']); } findTransactionsQuery(args, count) { if (args.partial.rawTx) throw new index_all_1.sdk.WERR_INVALID_PARAMETER('args.partial.rawTx', `undefined. Transactions may not be found by rawTx value.`); if (args.partial.inputBEEF) throw new index_all_1.sdk.WERR_INVALID_PARAMETER('args.partial.inputBEEF', `undefined. Transactions may not be found by inputBEEF value.`); const q = this.setupQuery('transactions', args); if (args.status && args.status.length > 0) q.whereIn('status', args.status); if (args.noRawTx && !count) { const columns = index_all_2.table.transactionColumnsWithoutRawTx.map(c => `transactions.${c}`); q.select(columns); } return q; } async findTransactions(args) { const q = this.findTransactionsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), transactionId: (0, index_all_1.verifyInteger)(d.transactionId), userId: (0, index_all_1.verifyInteger)(d.userId), status: (0, index_all_1.verifyTruthy)(convertTxStatus(d.status)), reference: forceToBase64(d.referenceNumber), isOutgoing: !!d.isOutgoing, satoshis: (0, index_all_1.verifyInteger)(d.amount), description: (0, index_all_1.verifyTruthy)(d.note || ''), provenTxId: verifyOptionalInteger(d.provenTxId), version: verifyOptionalInteger(d.version), lockTime: verifyOptionalInteger(d.lockTime), txid: nullToUndefined(d.txid), inputBEEF: d.beef ? Array.from(d.beef) : undefined, rawTx: d.rawTransaction ? Array.from(d.rawTransaction) : undefined, }; rs.push(r); } return this.validateEntities(rs, undefined, ['isOutgoing']); } findCommissionsQuery(args) { if (args.partial.lockingScript) throw new index_all_1.sdk.WERR_INVALID_PARAMETER('args.partial.lockingScript', `undefined. Commissions may not be found by lockingScript value.`); return this.setupQuery('commissions', args); } async findCommissions(args) { const q = this.findCommissionsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), commissionId: (0, index_all_1.verifyInteger)(d.commissionId), userId: (0, index_all_1.verifyInteger)(d.userId), transactionId: (0, index_all_1.verifyInteger)(d.transactionId), satoshis: (0, index_all_1.verifyInteger)(d.satoshis), keyOffset: (0, index_all_1.verifyTruthy)(d.keyOffset).trim(), isRedeemed: !!d.isRedeemed, lockingScript: Array.from((0, index_all_1.verifyTruthy)(d.outputScript)) }; rs.push(r); } return this.validateEntities(rs, undefined, ['isRedeemed']); } limitString(s, maxLen) { if (s.length > maxLen) s = s.slice(0, maxLen); return s; } findOutputsQuery(args, count) { if (args.partial.lockingScript) throw new index_all_1.sdk.WERR_INVALID_PARAMETER('args.partial.lockingScript', `undefined. Outputs may not be found by lockingScript value.`); const q = this.setupQuery('outputs', args); if (args.noScript && !count) { const columns = index_all_2.table.outputColumnsWithoutLockingScript.map(c => `outputs.${c}`); q.select(columns); } return q; } async findOutputs(args) { const q = this.findOutputsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), outputId: (0, index_all_1.verifyInteger)(d.outputId), userId: (0, index_all_1.verifyInteger)(d.userId), transactionId: (0, index_all_1.verifyInteger)(d.transactionId), basketId: verifyOptionalInteger(d.basketId), spendable: !!d.spendable, change: d.providedBy !== 'you' && d.purpose === 'change', outputDescription: (d.description || '').trim(), vout: (0, index_all_1.verifyInteger)(d.vout), satoshis: (0, index_all_1.verifyInteger)(d.amount), providedBy: (0, index_all_1.verifyTruthy)(d.providedBy || '').trim().toLowerCase().replace('dojo', 'storage'), purpose: (0, index_all_1.verifyTruthy)(d.purpose || '').trim().toLowerCase(), type: (0, index_all_1.verifyTruthy)(d.type).trim(), txid: nullToUndefined(d.txid), senderIdentityKey: (0, index_all_1.verifyOptionalHexString)(d.senderIdentityKey), derivationPrefix: nullToUndefined(d.derivationPrefix), derivationSuffix: nullToUndefined(d.derivationSuffix), customInstructions: nullToUndefined(d.customInstruction), spentBy: verifyOptionalInteger(d.spentBy), sequenceNumber: undefined, spendingDescription: nullToUndefined(d.spendingDescription), scriptLength: verifyOptionalInteger(d.scriptLength), scriptOffset: verifyOptionalInteger(d.scriptOffset), lockingScript: d.outputScript ? Array.from(d.outputScript) : undefined, }; rs.push(r); } return this.validateEntities(rs, undefined, ['spendable', 'change']); } findCertificatesQuery(args) { const q = this.setupQuery('certificates', args); if (args.certifiers && args.certifiers.length > 0) q.whereIn('certifier', args.certifiers); if (args.types && args.types.length > 0) q.whereIn('type', args.types); return q; } async findCertificates(args) { const q = this.findCertificatesQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), certificateId: (0, index_all_1.verifyInteger)(d.certificateId), userId: (0, index_all_1.verifyInteger)(d.userId), type: (0, index_all_1.verifyTruthy)(d.type).trim(), // base64 serialNumber: (0, index_all_1.verifyTruthy)(d.serialNumber).trim(), // base64 certifier: (0, index_all_1.verifyHexString)(d.certifier), subject: (0, index_all_1.verifyHexString)(d.subject), revocationOutpoint: (0, index_all_1.verifyTruthy)(d.revocationOutpoint).trim().toLowerCase(), signature: (0, index_all_1.verifyHexString)(d.signature), verifier: (0, index_all_1.verifyOptionalHexString)(d.validationKey), isDeleted: !!d.isDeleted }; rs.push(r); } return this.validateEntities(rs, undefined, ['isDeleted']); } findCertificateFieldsQuery(args) { return this.setupQuery('certificate_fields', args); } async findCertificateFields(args) { const q = this.findCertificateFieldsQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), userId: (0, index_all_1.verifyInteger)(d.userId), certificateId: (0, index_all_1.verifyInteger)(d.certificateId), fieldName: (0, index_all_1.verifyTruthy)(d.fieldName).trim().toLowerCase(), fieldValue: (0, index_all_1.verifyTruthy)(d.fieldValue).trim(), // base64 masterKey: (0, index_all_1.verifyTruthy)(d.masterKey).trim(), // base64 }; rs.push(r); } return this.validateEntities(rs); } async findSyncStates(args) { const q = this.setupQuery('sync_state', args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), syncStateId: (0, index_all_1.verifyInteger)(d.syncStateId), userId: (0, index_all_1.verifyInteger)(d.userId), storageIdentityKey: (0, index_all_1.verifyHexString)(d.storageIdentityKey), storageName: (0, index_all_1.verifyTruthy)(d.storageName || 'legacy importer').trim().toLowerCase(), status: convertSyncStatus(d.status), init: !!d.init, refNum: (0, index_all_1.verifyTruthy)(d.refNum), syncMap: (0, index_all_1.verifyTruthy)(d.syncMap), when: d.when ? this.validateDate(d.when) : undefined, satoshis: verifyOptionalInteger(d.total), errorLocal: nullToUndefined(d.errorLocal), errorOther: nullToUndefined(d.errorOther), }; rs.push(r); } return this.validateEntities(rs, undefined, ['init']); } async findUsers(args) { const q = this.setupQuery('users', args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), userId: (0, index_all_1.verifyId)(d.userId), identityKey: (0, index_all_1.verifyTruthy)(d.identityKey) }; rs.push(r); } return this.validateEntities(rs); } getProvenTxsForUserQuery(args) { const k = this.toDb(args.trx); let q = k('proven_txs').where(function () { this.whereExists(k.select('*').from('transactions').whereRaw(`proven_txs.provenTxId = transactions.provenTxId and transactions.userId = ${args.userId}`)); }); if (args.paged) { q = q.limit(args.paged.limit); q = q.offset(args.paged.offset || 0); } if (args.since) q = q.where('updated_at', '>=', args.since); return q; } async getProvenTxsForUser(args) { const q = this.getProvenTxsForUserQuery(args); const ds = await q; const rs = []; for (const d of ds) { const mp = (0, index_all_1.convertProofToMerklePath)(d.txid, { index: d.index, nodes: deserializeTscMerkleProofNodes(d.nodes), height: d.height }); const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), provenTxId: (0, index_all_1.verifyInteger)(d.provenTxId), txid: (0, index_all_1.verifyHexString)(d.txid), height: (0, index_all_1.verifyInteger)(d.height), index: (0, index_all_1.verifyInteger)(d.index), merklePath: mp.toBinary(), rawTx: Array.from((0, index_all_1.verifyTruthy)(d.rawTx)), blockHash: (0, index_all_1.verifyHexString)((0, index_all_1.asString)((0, index_all_1.verifyTruthy)(d.blockHash))), merkleRoot: (0, index_all_1.verifyHexString)((0, index_all_1.asString)((0, index_all_1.verifyTruthy)(d.merkleRoot))), }; rs.push(r); } return this.validateEntities(rs); } getProvenTxReqsForUserQuery(args) { const k = this.toDb(args.trx); let q = k('proven_tx_reqs').where(function () { this.whereExists(k.select('*').from('transactions').whereRaw(`proven_tx_reqs.txid = transactions.txid and transactions.userId = ${args.userId}`)); }); if (args.paged) { q = q.limit(args.paged.limit); q = q.offset(args.paged.offset || 0); } if (args.since) q = q.where('updated_at', '>=', args.since); return q; } async getProvenTxReqsForUser(args) { const q = this.getProvenTxReqsForUserQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), provenTxReqId: (0, index_all_1.verifyInteger)(d.provenTxReqId), provenTxId: verifyOptionalInteger(d.provenTxId), txid: (0, index_all_1.verifyTruthy)(d.txid), rawTx: Array.from((0, index_all_1.verifyTruthy)(d.rawTx)), status: (0, index_all_1.verifyTruthy)(convertReqStatus(d.status)), attempts: (0, index_all_1.verifyInteger)(d.attempts), notified: !!d.notified, history: (0, index_all_1.verifyTruthy)(d.history), notify: (0, index_all_1.verifyTruthy)(d.notify), inputBEEF: d.beef ? Array.from(d.beef) : undefined }; rs.push(r); } return this.validateEntities(rs, undefined, ['notified']); } getTxLabelMapsForUserQuery(args) { const k = this.toDb(args.trx); let q = k('tx_labels_map') .whereExists(k.select('*').from('tx_labels').whereRaw(`tx_labels.txLabelId = tx_labels_map.txLabelId and tx_labels.userId = ${args.userId}`)); if (args.since) q = q.where('updated_at', '>=', this.validateDateForWhere(args.since)); if (args.paged) { q = q.limit(args.paged.limit); q = q.offset(args.paged.offset || 0); } return q; } async getTxLabelMapsForUser(args) { const q = this.getTxLabelMapsForUserQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), txLabelId: (0, index_all_1.verifyInteger)(d.txLabelId), transactionId: (0, index_all_1.verifyInteger)(d.transactionId), isDeleted: !!d.isDeleted }; rs.push(r); } return this.validateEntities(rs, undefined, ['isDeleted']); } getOutputTagMapsForUserQuery(args) { const k = this.toDb(args.trx); let q = k('output_tags_map') .whereExists(k.select('*').from('output_tags').whereRaw(`output_tags.outputTagId = output_tags_map.outputTagId and output_tags.userId = ${args.userId}`)); if (args.since) q = q.where('updated_at', '>=', this.validateDateForWhere(args.since)); if (args.paged) { q = q.limit(args.paged.limit); q = q.offset(args.paged.offset || 0); } return q; } async getOutputTagMapsForUser(args) { const q = this.getOutputTagMapsForUserQuery(args); const ds = await q; const rs = []; for (const d of ds) { const r = { created_at: (0, index_all_1.verifyTruthy)(d.created_at), updated_at: (0, index_all_1.verifyTruthy)(d.updated_at), outputId: (0, index_all_1.verifyInteger)(d.outputId), outputTagId: (0, index_all_1.verifyInteger)(d.outputTagId), isDeleted: !!d.isDeleted }; rs.push(r); } return this.validateEntities(rs, undefined, ['isDeleted']); } countCertificateFields(args) { throw new Error('Method not implemented.'); } countCertificates(args) { throw new Error('Method not implemented.'); } countCommissions(args) { throw new Error('Method not implemented.'); } countOutputBaskets(args) { throw new Error('Method not implemented.'); } countOutputs(args) { throw new Error('Method not implemented.'); } countOutputTags(args) { throw new Error('Method not implemented.'); } countSyncStates(args) { throw new Error('Method not implemented.'); } countTransactions(args) { throw new Error('Method not implemented.'); } countTxLabels(args) { throw new Error('Method not implemented.'); } countUsers(args) { throw new Error('Method not implemented.'); } findMonitorEvents(args) { throw new Error('Method not implemented.'); } countMonitorEvents(args) { throw new Error('Method not implemented.'); } /** * Helper to force uniform behavior across database engines. * Use to process all individual records with time stamps retreived from database. */ validateEntity(entity, dateFields, booleanFields) { entity.created_at = this.validateDate(entity.created_at); entity.updated_at = this.validateDate(entity.updated_at); if (dateFields) { for (const df of dateFields) { if (entity[df]) entity[df] = this.validateDate(entity[df]); } } if (booleanFields) { for (const df of booleanFields) { if (entity[df] !== undefined) entity[df] = !!(entity[df]); } } for (const key of Object.keys(entity)) { const val = entity[key]; if (val === null) { entity[key] = undefined; } else if (Buffer.isBuffer(val)) { entity[key] = Array.from(val); } } return entity; } /** * Helper to force uniform behavior across database engines. * Use to process all arrays of records with time stamps retreived from database. * @returns input `entities` array with contained values validated. */ validateEntities(entities, dateFields, booleanFields) { for (let i = 0; i < entities.length; i++) { entities[i] = this.validateEntity(entities[i], dateFields, booleanFields); } return entities; } } exports.StorageMySQLDojoReader = StorageMySQLDojoReader; function deserializeTscMerkleProofNodes(nodes) { if (!Buffer.isBuffer(nodes)) throw new index_all_1.sdk.WERR_INTERNAL('Buffer or string expected.'); const buffer = nodes; const ns = []; for (let offset = 0; offset < buffer.length;) { const flag = buffer[offset++]; if (flag === 1) ns.push('*'); else if (flag === 0) { ns.push((0, index_all_1.asString)(buffer.subarray(offset, offset + 32))); offset += 32; } else { throw new index_all_1.sdk.WERR_BAD_REQUEST(`node type byte ${flag} is not supported here.`); } } return ns; } function convertReqStatus(status) { return status; } //type TransactionStatus = // 'completed' | 'failed' | 'unprocessed' | 'sending' | 'unproven' | 'unsigned' | 'nosend' function convertTxStatus(status) { return status; } function nullToUndefined(v) { if (v === null) return undefined; if (typeof v === 'string') return v.trim(); return v; } function verifyOptionalInteger(v) { if (v === undefined || v === null) return undefined; if (typeof v !== 'number' || !Number.isInteger(v)) throw new index_all_1.sdk.WERR_INTERNAL('An integer is required.'); return v; } function convertSyncStatus(status) { return status; } function forceToBase64(s) { if (!s) return (0, index_all_1.randomBytesBase64)(12); if ((0, sdk_2.isHexString)(s)) return sdk_1.Utils.toBase64((0, index_all_1.asArray)(s.trim())); return s.trim(); } //# sourceMappingURL=StorageMySQLDojoReader.js.map