chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

chore: version 2.1.2 - #859

Merged
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2
Mar 24, 2026
Merged

chore: version 2.1.2#859
piotr-iohk merged 2 commits into
masterfrom
release-2.1.2

Conversation

@ovitrif

@ovitrifovitrif commented Mar 20, 2026

Copy link
Copy Markdown
Collaborator

Fixes: #847

Release 2.1.2 — includes stale channel monitors recovery and version bump.

Note: This PR replaces #855 which was auto-closed by GitHub when the base branch was force-pushed. It could not be reopened, so this release PR supersedes it.

see also:

Description

  • Stale channel monitors recovery: When a channel monitor falls behind the channel manager (e.g. due to faulty overwrite during an unfiltered migration from LDK to ldk-node), ldk-node refuses to start with a DangerousValue error to protect funds. This catches that error and retries the build with accept_stale_channel_monitors enabled, allowing ldk-node to accept the stale monitor and self-heal via commitment round-trips with the channel peer.
  • Adds a 10s connection timeout to the node config, as required by ldk-node rc.33.
  • versionCode: 179 → 180
  • versionName: 2.1.1 → 2.1.2

Preview

Screenshot of activity list after recovery.
The transactions are part of the setup to reproduce the issue.

QA Notes

1. Normal startup (unaffected users)

  1. Install the build on a device with an existing wallet
  2. Launch the app
  3. Verify the node starts normally with no warnings in logs
  4. Verify all balances and channels appear correctly

2. Stale monitor recovery

  1. Reproduce the stale monitor state, see test plan
  2. App should be in broken state now: node fails to start
  3. Run 2.1.2
  4. Verify the healing fix succeeds and app starts with a fully functional node and LN channel
  5. Check logs for DangerousValue and accept_stale_channel_monitors
  6. Verify Stale monitor recovery: all monitors healed appears in logs within ~15s
  7. Kill and relaunch — verify normal startup & no retry logs, since monitors are now healed

3. Connection timeout (optional)

  1. Verify the node respects the 10s connection timeout (observable in poor network conditions)

chore: update ldk-node to 0.7.0-rc.36
chore: review
chore: bump ldk-node to rc.35
@ovitrifovitrif self-assigned this Mar 20, 2026
@claude

claudeBot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip

  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

@jvsena42

Copy link
Copy Markdown
Member

Exercised the full matrix in repro-channel-monitor-desync.md#test-plan against this build. All targeted scenarios passed.

Observations (I believe non-blocking, but sharing to double-check):

  • Scenario B7 (Blocktank channel: v2.1.0 broken wallet + 600 blocks mined → v2.1.2 (stale chain state)): Recovery completed (DangerousValue → setAcceptStaleChannelMonitors, healing payment, monitors healed). Immediately after startup, LN send/receive briefly showed “route not found” toast; after a short time / a few attempts, payments succeeded. Likely regtest RGS empty/stale + graph warm-up rather than a failed recovery. Sharing logs to double check.
    logs-b7-android.zip
  • Scenarios T2 / T5 (3rd-party / local LND: Update broken v2.1.0 wallet to v2.1.2): Recovery/end-to-end took longer than Blocktank cases; run hit a timeout. In the end it recovered, but took over a minute in both cases
    logs-t2-android.zip
    logs-t5-android.zip

✅ Confirmed, these are non-blocking behaviors. From the logs:

  • B7 : The recovery succeed, but the network graph was reject as stale "Rapid Gossip Sync data is more than two weeks old" with RGS timestamp = 0, and then succeeds once graph populates. This is an expected behavior in regtest. On mainnet, RGS will have a valid snapshot, so the graph won't be empty after recovery. The aresRequiredPeersInNetworkGraph() validation at LightningRepo.kt:336 would also catch and reset a stale graph on mainnet if needed.

  • T2/T5: The recover also succeeded eventually. LND took longer because it rejected the healing payment with IncorrectPaymentDetails, so the remaining path to healing was waiting for normal channel reestablishment after the timeout

@piotr-iohk
piotr-iohk merged commit f257824 into masterMar 24, 2026
19 checks passed
@piotr-iohk
piotr-iohk deleted the release-2.1.2 branch March 24, 2026 19:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: VSS ChannelMonitor desync causes unrecoverable "LDK Build error: Read failed" on wallet restore

3 participants

@ovitrif@piotr-iohk@jvsena42