-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
What I got so far:
- Blocktank node is a
trustedLnPeers - Trusted peer channels use anchor outputs
- Anchor outputs have a different outputs scripts with different CSV conditions
DEBUG: Current block height: 31732
WARN⚠️: 🔑 CLAIMABLE HEIGHT: 0 ← Output becomes spendable at this block
WARN⚠️: ⚠️ Claimable height is 0 - this may indicate LDK hasn't calculated the timelock yet
LDK has claimableHeight = 0, which means LDK is failing to calculate when this force-close output becomes spendable. This is why the funds are stuck indefinitely.
External node channels are not on trusted list so they use a non-anchor channel format. That is why it worked on the tests
Another strange this is that transactionName = 0
It suggests LDK might be completely missing the force-close transaction details.
It would be helpful is I could see the commitment transaction in the mempool
WARN⚠️: 📄 TRANSACTION NAME/ID: 0
WARN⚠️: 🔑 CLAIMABLE HEIGHT: 0 ← Output becomes spendable at this block
WARN⚠️: ⚠️ Claimable height is 0 - this may indicate LDK hasn't calculated the timelock yet
WARN⚠️: 🔍 ANCHOR CHANNEL BUG: LDK cannot determine when CSV timelock expires
func sync() async throws {
guard let node else {
throw AppError(serviceError: .nodeNotSetup)
}
Logger.debug("Syncing LDK...")
try await ServiceQueue.background(.ldk) {
try node.syncWallets()
// try? self.setMaxDustHtlcExposureForCurrentChannels()
}
Logger.info("LDK synced")
await refreshChannelCache()
// Log detailed balance information after sync
let balanceDetails = node.listBalances()
let nodeStatus = node.status()
let currentHeight = nodeStatus.currentBestBlock.height
Logger.debug("=== LDK Balance Details After Sync ===")
Logger.debug("Current block height: \(currentHeight)")
Logger.debug("Total onchain: \(balanceDetails.totalOnchainBalanceSats) sats")
Logger.debug("Total lightning: \(balanceDetails.totalLightningBalanceSats) sats")
Logger.debug("Lightning balances count: \(balanceDetails.lightningBalances.count)")
for (index, balance) in balanceDetails.lightningBalances.enumerated() {
Logger.debug("Lightning Balance #\(index + 1):")
switch balance {
case let .claimableOnChannelClose(
channelId,
counterpartyNodeId,
amountSat,
transactionName,
confirmationHeight,
claimableHeight,
paymentHash,
paymentPreimage
):
Logger.warn(" Type: ClaimableOnChannelClose")
Logger.warn(" ⚠️ This is a FORCE-CLOSED channel balance waiting to be claimed!")
Logger.debug(" Channel ID: \(channelId)")
Logger.debug(" Amount: \(amountSat) sats")
Logger.warn(" 📄 TRANSACTION NAME/ID: \(transactionName)")
Logger.debug(" Confirmation height: \(confirmationHeight)")
Logger.warn(" 🔑 CLAIMABLE HEIGHT: \(claimableHeight) ← Output becomes spendable at this block")
// Calculate blocks remaining until claimable
let currentHeightUInt64 = UInt64(currentHeight)
if claimableHeight > currentHeightUInt64 {
let blocksRemaining = claimableHeight - currentHeightUInt64
Logger.warn(" ⏰ Blocks until claimable: \(blocksRemaining) (need to mine \(blocksRemaining) more blocks)")
} else if claimableHeight > 0 {
Logger.warn(" ✅ Output is NOW CLAIMABLE (claimable height \(claimableHeight) <= current height \(currentHeight))")
Logger.warn(" 🚨 LDK should sweep this automatically - if it hasn't, there may be an issue")
} else {
Logger.warn(" ⚠️ Claimable height is 0 - this may indicate LDK hasn't calculated the timelock yet")
Logger.warn(" 🔍 ANCHOR CHANNEL BUG: LDK cannot determine when CSV timelock expires")
Logger.warn(" 💡 This is a known issue with anchor channels - funds are stuck until LDK is fixed or manual intervention")
}
if paymentHash != 0 {
Logger.debug(" Payment hash: \(paymentHash)")
}
if paymentPreimage != 0 {
Logger.debug(" Payment preimage: \(paymentPreimage)")
}
Logger.debug(" Counterparty: \(counterpartyNodeId)")
case let .claimableAwaitingConfirmations(channelId, counterpartyNodeId, amountSat, confirmationHeight, transactionName):
Logger.info(" Type: ClaimableAwaitingConfirmations")
Logger.info(" ⏳ Sweep transaction is pending, waiting for confirmations")
Logger.debug(" Transaction: \(transactionName)")
Logger.debug(" Confirmation height: \(confirmationHeight)")
Logger.debug(" Counterparty: \(counterpartyNodeId)")
case .contentiousClaimable:
Logger.warn(" Type: ContentiousClaimable")
case .maybeTimeoutClaimableHtlc:
Logger.debug(" Type: MaybeTimeoutClaimableHTLC")
case .maybePreimageClaimableHtlc:
Logger.debug(" Type: MaybePreimageClaimableHTLC")
case .counterpartyRevokedOutputClaimable:
Logger.warn(" Type: CounterpartyRevokedOutputClaimable")
}
}
Logger.debug("=====================================")
// Emit state change with sync timestamp from node status
if let latestSyncTimestamp = nodeStatus.latestLightningWalletSyncTimestamp {
let syncTimestamp = UInt64(latestSyncTimestamp)
syncStatusChangedSubject.send(syncTimestamp)
} else {
let syncTimestamp = UInt64(Date().timeIntervalSince1970)
syncStatusChangedSubject.send(syncTimestamp)
}
}
Originally posted by @jvsena42 in #207 (comment)
Metadata
Metadata
Assignees
Labels
No labels