UNPKG

@bsv/sdk

Version:

BSV Blockchain Software Development Kit

54 lines 2.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.withDoubleSpendRetry = withDoubleSpendRetry; const Transaction_js_1 = __importDefault(require("../transaction/Transaction.js")); /** * Maximum number of retry attempts for double-spend resolution */ const MAX_DOUBLE_SPEND_RETRIES = 5; /** * Executes an operation with automatic retry logic for double-spend errors. * When a double-spend is detected, broadcasts the competing transaction to * update the overlay with missing state, then retries the operation. * * @param operation - The async operation to execute (e.g., createAction + signAction) * @param broadcaster - The TopicBroadcaster to use for syncing missing state * @param maxRetries - Maximum number of retry attempts (default: MAX_DOUBLE_SPEND_RETRIES) * @returns The result of the successful operation * @throws If max retries exceeded or non-double-spend error occurs */ async function withDoubleSpendRetry(operation, broadcaster, maxRetries = MAX_DOUBLE_SPEND_RETRIES) { let attempts = 0; while (attempts < maxRetries) { attempts++; try { return await operation(); } catch (error) { // Only handle double-spend errors on non-final attempts if (attempts < maxRetries && error.name === 'WERR_REVIEW_ACTIONS') { const reviewError = error; // Check if any action in the batch has a double-spend const doubleSpendResult = reviewError.reviewActionResults.find((result) => result.status === 'doubleSpend'); if (doubleSpendResult?.competingBeef != null && doubleSpendResult?.competingTxs != null && doubleSpendResult?.competingTxs.length > 0) { const competingTx = Transaction_js_1.default.fromBEEF(doubleSpendResult.competingBeef, doubleSpendResult.competingTxs[0]); // Recursively handle double-spend errors during broadcast // The broadcast itself might fail if the competing tx depends on another missing tx await withDoubleSpendRetry(async () => await broadcaster.broadcast(competingTx), broadcaster, maxRetries - attempts // Reduce max retries based on attempts already used ); continue; } } // Non-double-spend error or max retries exceeded - rethrow throw error; } } // This should never be reached, but TypeScript requires it throw new Error('Unexpected end of retry loop'); } //# sourceMappingURL=withDoubleSpendRetry.js.map