UNPKG

@bsv/overlay

Version:
217 lines 8.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.KnexStorage = void 0; class KnexStorage { constructor(knex) { this.knex = knex; } async findOutput(txid, outputIndex, topic, spent, includeBEEF = false) { const search = { 'outputs.txid': txid, 'outputs.outputIndex': outputIndex }; if (topic !== undefined) search['outputs.topic'] = topic; if (spent !== undefined) search['outputs.spent'] = spent; // Base query to get the output const query = this.knex('outputs').where(search); // Select necessary fields from outputs and conditionally include beef from transactions const selectFields = [ 'outputs.txid', 'outputs.outputIndex', 'outputs.outputScript', 'outputs.topic', 'outputs.satoshis', 'outputs.outputsConsumed', 'outputs.spent', 'outputs.consumedBy', 'outputs.score' ]; if (includeBEEF) { // eslint-disable-next-line @typescript-eslint/no-floating-promises query.leftJoin('transactions', 'outputs.txid', 'transactions.txid'); selectFields.push('transactions.beef'); } const output = await query.select(selectFields).first(); if (output === undefined || output === null) { return null; } return { ...output, outputScript: [...output.outputScript], beef: includeBEEF ? (output.beef !== undefined ? [...output.beef] : undefined) : undefined, spent: Boolean(output.spent), outputsConsumed: JSON.parse(output.outputsConsumed), consumedBy: JSON.parse(output.consumedBy) }; } async findOutputsForTransaction(txid, includeBEEF = false) { // Base query to get outputs const query = this.knex('outputs').where({ 'outputs.txid': txid }); // Select necessary fields from outputs and conditionally include beef from transactions const selectFields = [ 'outputs.txid', 'outputs.outputIndex', 'outputs.outputScript', 'outputs.topic', 'outputs.satoshis', 'outputs.outputsConsumed', 'outputs.spent', 'outputs.consumedBy', 'outputs.score' ]; if (includeBEEF) { // eslint-disable-next-line @typescript-eslint/no-floating-promises query.leftJoin('transactions', 'outputs.txid', 'transactions.txid'); selectFields.push('transactions.beef'); } const outputs = await query.select(selectFields); if (outputs === undefined || outputs.length === 0) { return []; } return outputs.map(output => ({ ...output, outputScript: [...output.outputScript], beef: includeBEEF ? (output.beef !== undefined ? [...output.beef] : undefined) : undefined, spent: Boolean(output.spent), outputsConsumed: JSON.parse(output.outputsConsumed), consumedBy: JSON.parse(output.consumedBy) })); } async findUTXOsForTopic(topic, since, limit, includeBEEF = false) { // Base query to get outputs const query = this.knex('outputs').where({ 'outputs.topic': topic, 'outputs.spent': false }); // If provided, additionally filters UTXOs by score if (since !== undefined && since > 0) { // eslint-disable-next-line @typescript-eslint/no-floating-promises query.andWhere('outputs.score', '>=', since); } // Sort by score // eslint-disable-next-line @typescript-eslint/no-floating-promises query.orderBy('outputs.score', 'asc'); // Select necessary fields from outputs and conditionally include beef from transactions const selectFields = [ 'outputs.txid', 'outputs.outputIndex', 'outputs.outputScript', 'outputs.topic', 'outputs.satoshis', 'outputs.outputsConsumed', 'outputs.spent', 'outputs.consumedBy', 'outputs.score' ]; if (includeBEEF) { // eslint-disable-next-line @typescript-eslint/no-floating-promises query.leftJoin('transactions', 'outputs.txid', 'transactions.txid'); selectFields.push('transactions.beef'); } // Apply limit if specified if (limit !== undefined && limit > 0) { // eslint-disable-next-line @typescript-eslint/no-floating-promises query.limit(limit); } const outputs = await query.select(selectFields); if (outputs === undefined || outputs.length === 0) { return []; } return outputs.map(output => ({ ...output, outputScript: [...output.outputScript], beef: includeBEEF ? (output.beef !== undefined ? [...output.beef] : undefined) : undefined, spent: Boolean(output.spent), outputsConsumed: JSON.parse(output.outputsConsumed), consumedBy: JSON.parse(output.consumedBy) })); } async deleteOutput(txid, outputIndex, _) { await this.knex.transaction(async (trx) => { // Delete the specific output await trx('outputs').where({ txid, outputIndex }).del(); // Check how many outputs reference the same transaction const remainingOutputs = await trx('outputs').where({ txid }).count('* as count').first(); if (remainingOutputs !== undefined && Number(remainingOutputs.count) === 0) { // If no more outputs reference the transaction, delete the beef await trx('transactions').where({ txid }).del(); } }); } async insertOutput(output) { const insertPromises = [this.knex('outputs').insert({ txid: output.txid, outputIndex: Number(output.outputIndex), outputScript: Buffer.from(output.outputScript), topic: output.topic, satoshis: Number(output.satoshis), outputsConsumed: JSON.stringify(output.outputsConsumed), consumedBy: JSON.stringify(output.consumedBy), spent: output.spent, score: output.score })]; if (output.beef !== undefined) { const insertTransactionPromise = this.knex('transactions').insert({ txid: output.txid, beef: Buffer.from(output.beef) }).onConflict('txid').ignore(); insertPromises.push(insertTransactionPromise); } await this.knex.transaction(async (trx) => { await Promise.all(insertPromises.map(promise => promise.transacting(trx))); }); } async markUTXOAsSpent(txid, outputIndex, topic) { await this.knex('outputs').where({ txid, outputIndex, topic }).update('spent', true); } async updateConsumedBy(txid, outputIndex, topic, consumedBy) { await this.knex('outputs').where({ txid, outputIndex, topic }).update('consumedBy', JSON.stringify(consumedBy)); } async updateTransactionBEEF(txid, beef) { await this.knex('transactions').where({ txid }).update('beef', Buffer.from(beef)); } async updateOutputBlockHeight(txid, outputIndex, topic, blockHeight) { await this.knex('outputs').where({ txid, outputIndex, topic }).update('blockHeight', blockHeight); } async insertAppliedTransaction(tx) { await this.knex('applied_transactions').insert({ txid: tx.txid, topic: tx.topic }); } async doesAppliedTransactionExist(tx) { const result = await this.knex('applied_transactions') .where({ txid: tx.txid, topic: tx.topic }) .select(this.knex.raw('1')) .first(); return !!result; } async updateLastInteraction(host, topic, since) { await this.knex('host_sync_state') .insert({ host, topic, since }) .onConflict(['host', 'topic']) .merge({ since }); } async getLastInteraction(host, topic) { const result = await this.knex('host_sync_state') .where({ host, topic }) .select('since') .first(); return result ? result.since : 0; } } exports.KnexStorage = KnexStorage; //# sourceMappingURL=KnexStorage.js.map