Skip to content

Commit b3718c7

Browse files
authored
Merge pull request #267 from synonymdev/spend-outputs-fix
fix: spend outputs script checks unconfirmed and confirmed broadcasted txs
2 parents 0f68c43 + 79c075f commit b3718c7

File tree

6 files changed

+75
-34
lines changed

6 files changed

+75
-34
lines changed

lib/android/src/main/java/com/reactnativeldk/LdkModule.kt

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,7 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
12281228
}
12291229

12301230
@ReactMethod
1231-
fun spendRecoveredForceCloseOutputs(transaction: String, confirmationHeight: Double, changeDestinationScript: String, promise: Promise) {
1231+
fun spendRecoveredForceCloseOutputs(transaction: String, confirmationHeight: Double, changeDestinationScript: String, useInner: Boolean, promise: Promise) {
12321232
if (channelStoragePath == "") {
12331233
return handleReject(promise, LdkErrors.init_storage_path)
12341234
}
@@ -1270,13 +1270,23 @@ class LdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
12701270
continue
12711271
}
12721272

1273-
val res = keysManager!!.spend_spendable_outputs(
1274-
descriptors,
1275-
emptyArray(),
1276-
changeDestinationScript.hexa(),
1277-
feeEstimator.onChainSweep,
1278-
Option_u32Z.none()
1279-
)
1273+
val res = if (useInner) {
1274+
keysManager!!.inner.spend_spendable_outputs(
1275+
descriptors,
1276+
emptyArray(),
1277+
changeDestinationScript.hexa(),
1278+
feeEstimator.onChainSweep,
1279+
Option_u32Z.none()
1280+
)
1281+
} else {
1282+
keysManager!!.spend_spendable_outputs(
1283+
descriptors,
1284+
emptyArray(),
1285+
changeDestinationScript.hexa(),
1286+
feeEstimator.onChainSweep,
1287+
Option_u32Z.none()
1288+
)
1289+
}
12801290

12811291
if (res.is_ok) {
12821292
txs.pushHexString((res as Result_TransactionNoneZ.Result_TransactionNoneZ_OK).res)

lib/ios/Ldk.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ @interface RCT_EXTERN_MODULE(Ldk, NSObject)
176176
RCT_EXTERN_METHOD(spendRecoveredForceCloseOutputs:(NSString *)transaction
177177
confirmationHeight:(NSInteger *)confirmationHeight
178178
changeDestinationScript:(NSString *)changeDestinationScript
179+
useInner:(BOOL *)useInner
179180
resolve:(RCTPromiseResolveBlock)resolve
180181
reject:(RCTPromiseRejectBlock)reject)
181182
RCT_EXTERN_METHOD(nodeSign:(NSString *)message

lib/ios/Ldk.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ class Ldk: NSObject {
507507
currentBlockchainHeight = blockHeight
508508
addForegroundObserver()
509509
startDroppedPeerTimer()
510-
510+
511511
return handleResolve(resolve, .channel_manager_init_success)
512512
}
513513

@@ -659,7 +659,7 @@ class Ldk: NSObject {
659659
guard let self else { return }
660660

661661
LdkEventEmitter.shared.send(withEvent: .native_log, body: "Starting timer to check for dropped peers")
662-
662+
663663
droppedPeerTimer = Timer.scheduledTimer(
664664
timeInterval: 5.0,
665665
target: self,
@@ -1385,7 +1385,7 @@ class Ldk: NSObject {
13851385
}
13861386

13871387
@objc
1388-
func spendRecoveredForceCloseOutputs(_ transaction: NSString, confirmationHeight: NSInteger, changeDestinationScript: NSString, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1388+
func spendRecoveredForceCloseOutputs(_ transaction: NSString, confirmationHeight: NSInteger, changeDestinationScript: NSString, useInner: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
13891389

13901390
guard let channelStoragePath = Ldk.channelStoragePath, let keysManager, let channelManager else {
13911391
return handleReject(reject, .init_storage_path)
@@ -1428,7 +1428,14 @@ class Ldk: NSObject {
14281428
continue
14291429
}
14301430

1431-
let res = keysManager.spendSpendableOutputs(
1431+
let res = useInner ? keysManager.inner.spendSpendableOutputs(
1432+
descriptors: descriptors,
1433+
outputs: [],
1434+
changeDestinationScript: String(changeDestinationScript).hexaBytes,
1435+
feerateSatPer1000Weight: feeEstimator.getEstSatPer1000Weight(confirmationTarget: .OnChainSweep),
1436+
locktime: nil)
1437+
:
1438+
keysManager.spendSpendableOutputs(
14321439
descriptors: descriptors,
14331440
outputs: [],
14341441
changeDestinationScript: String(changeDestinationScript).hexaBytes,

lib/src/ldk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,12 +1249,14 @@ class LDK {
12491249
transaction,
12501250
confirmationHeight,
12511251
changeDestinationScript,
1252+
useInner,
12521253
}: TSpendRecoveredForceCloseOutputsReq): Promise<Result<string[]>> {
12531254
try {
12541255
const res = await NativeLDK.spendRecoveredForceCloseOutputs(
12551256
transaction,
12561257
confirmationHeight,
12571258
changeDestinationScript,
1259+
useInner,
12581260
);
12591261
this.writeDebugToLog('spendRecoveredForceCloseOutputs', res);
12601262
return ok(res);

lib/src/lightning-manager.ts

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,14 +1637,26 @@ class LightningManager {
16371637
* Returns previously broadcasted transactions saved in storgare.
16381638
* @returns {Promise<TLdkBroadcastedTransactions>}
16391639
*/
1640-
async getLdkBroadcastedTxs(): Promise<TLdkBroadcastedTransactions> {
1640+
async getLdkBroadcastedTxs(
1641+
includeConfirmed: boolean = false,
1642+
): Promise<TLdkBroadcastedTransactions> {
1643+
let txs: TLdkBroadcastedTransactions = [];
16411644
const res = await ldk.readFromFile({
16421645
fileName: ELdkFiles.broadcasted_transactions,
16431646
});
16441647
if (res.isOk()) {
1645-
return parseData(res.value.content, []);
1648+
txs = parseData(res.value.content, []);
16461649
}
1647-
return [];
1650+
1651+
if (includeConfirmed) {
1652+
const confirmedRes = await ldk.readFromFile({
1653+
fileName: ELdkFiles.confirmed_broadcasted_transactions,
1654+
});
1655+
if (confirmedRes.isOk()) {
1656+
txs = txs.concat(parseData(confirmedRes.value.content, []));
1657+
}
1658+
}
1659+
return txs;
16481660
}
16491661

16501662
async cleanupBroadcastedTxs(): Promise<void> {
@@ -1766,33 +1778,41 @@ class LightningManager {
17661778
return err('Unable to retrieve change_destination_script.');
17671779
}
17681780

1769-
const txs = await this.getLdkBroadcastedTxs();
1781+
const txs = await this.getLdkBroadcastedTxs(true);
17701782
if (!txs.length) {
17711783
return ok('No outputs to reconstruct as no cached transactions found.');
17721784
}
17731785

17741786
let txsToBroadcast = 0;
1775-
for (const hexTx of txs) {
1776-
const tx = bitcoin.Transaction.fromHex(hexTx);
1777-
const txData = await this.getTransactionData(tx.getId());
17781787

1779-
const txsRes = await ldk.spendRecoveredForceCloseOutputs({
1780-
transaction: hexTx,
1781-
confirmationHeight: txData?.height ?? 0,
1782-
changeDestinationScript,
1783-
});
1788+
const processTxs = async (useInner: boolean): Promise<void> => {
1789+
for (const hexTx of txs) {
1790+
const tx = bitcoin.Transaction.fromHex(hexTx);
1791+
const txData = await this.getTransactionData(tx.getId());
17841792

1785-
if (txsRes.isErr()) {
1786-
await ldk.writeToLogFile('error', txsRes.error.message);
1787-
console.error(txsRes.error.message);
1788-
continue;
1789-
}
1793+
const txsRes = await ldk.spendRecoveredForceCloseOutputs({
1794+
transaction: hexTx,
1795+
confirmationHeight: txData?.height ?? 0,
1796+
changeDestinationScript,
1797+
useInner,
1798+
});
1799+
1800+
if (txsRes.isErr()) {
1801+
await ldk.writeToLogFile('error', txsRes.error.message);
1802+
console.error(txsRes.error.message);
1803+
continue;
1804+
}
17901805

1791-
for (const createdTx of txsRes.value) {
1792-
txsToBroadcast++;
1793-
await this.broadcastTransaction(createdTx);
1806+
for (const createdTx of txsRes.value) {
1807+
txsToBroadcast++;
1808+
await this.broadcastTransaction(createdTx);
1809+
}
17941810
}
1795-
}
1811+
};
1812+
1813+
//Process first using the inner (ldk keychain) and then using the custom keychain
1814+
await processTxs(true);
1815+
await processTxs(false);
17961816

17971817
return ok(`Attempting to reconstruct ${txsToBroadcast} transactions.`);
17981818
}

lib/src/utils/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export type TChannel = {
150150
balance_sat: number;
151151
counterparty_node_id: string;
152152
funding_txid?: string;
153-
funding_output_index? : number;
153+
funding_output_index?: number;
154154
channel_type?: string;
155155
user_channel_id: string;
156156
confirmations_required?: number;
@@ -613,6 +613,7 @@ export type TSpendRecoveredForceCloseOutputsReq = {
613613
transaction: string;
614614
confirmationHeight: number;
615615
changeDestinationScript: string;
616+
useInner: boolean;
616617
};
617618

618619
export type TBackupServerDetails = {

0 commit comments

Comments
 (0)