Skip to content

fix: match cjit entry to channel by funding tx#1017

Merged
ovitrif merged 17 commits into
masterfrom
fix/cjit-channel-false-match
Jun 19, 2026
Merged

fix: match cjit entry to channel by funding tx#1017
ovitrif merged 17 commits into
masterfrom
fix/cjit-channel-false-match

Conversation

@jvsena42

@jvsena42 jvsena42 commented Jun 16, 2026

Copy link
Copy Markdown
Member

This PR fixes the "Spending Balance Ready" confirmation not appearing after a successful Transfer to Spending when an unused instant-payment (CJIT) invoice is still pending.

Description

When a spending channel opens, the app decides whether the new channel came from a CJIT (instant-payment) invoice or from a paid channel order. Previously this match was done by comparing only the channel size and the LSP node pubkey. Because both flows use the same LSP and the same default channel sizing, a leftover unpaid CJIT entry of the same size would be mistaken for the freshly opened channel-order channel.

The side effects of that false match were:

  • the "Spending Balance Ready" toast was suppressed, and
  • the transfer was incorrectly treated as an incoming payment (a received transaction sheet and a spurious received Lightning activity).

The CJIT entry is now matched to a channel by its funding transaction id, which is the stable identifier that actually ties a CJIT entry to the channel it opened (mirroring the iOS matching). Entries are refreshed from the server first so a genuinely opened CJIT channel association is current before matching, with a fallback to cached state. A stale, unpaid CJIT entry has no opened channel and can no longer be mistaken for a channel-order channel.

Preview

without-cjit.webm
bug.webm
fix.webm
cjit.webm

QA Notes

Manual Tests

  • 1. Create an instant-payment invoice (Receive → Spending → enter amount → generate) but do not pay it, then Transfer to Spending the same amount → Confirm → swipe: "Spending Balance Ready" confirmation appears (not a received-payment sheet), and no spurious received activity is added.
  • 2. regression: No leftover CJIT invoice → Transfer to Spending → Confirm → swipe: "Spending Balance Ready" confirmation still appears.
  • 3. regression: Pay a real instant-payment (CJIT) invoice → channel opens: received-payment sheet and received Lightning activity still show as before.

Automated Checks

  • Unit tests added: cover CJIT-to-channel matching by funding tx in app/src/test/java/to/bitkit/repositories/BlocktankRepoTest.kt — stale unpaid entry is not matched, funding-tx match/no-match, and null funding txo.
  • CI: standard compile, unit test, and detekt checks run by the PR bot.

@jvsena42 jvsena42 self-assigned this Jun 16, 2026
@jvsena42 jvsena42 marked this pull request as ready for review June 18, 2026 12:20
@jvsena42 jvsena42 enabled auto-merge June 18, 2026 12:21
@jvsena42 jvsena42 added this to the 2.4.0 milestone Jun 18, 2026
@greptile-apps

greptile-apps Bot commented Jun 18, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a false-positive CJIT match that caused the "Spending Balance Ready" confirmation to be suppressed and a spurious received-payment sheet to appear after a Transfer to Spending when an unpaid CJIT invoice was still pending. The root cause — matching by channel size and LSP pubkey instead of the stable funding transaction outpoint — is replaced with an exact fundingTx.id + vout comparison, mirroring the iOS implementation.

  • BlocktankRepo.getCjitEntry now resolves the match by fundingTxo (txid + vout), with a server refresh guarded behind a "has pending CJIT" check and up to 3 retry attempts with TimeoutCancellationException treated as retriable per the AGENTS.md documented exception pattern.
  • runSuspendCatching is introduced in ext/Coroutines.kt and adopted in NotifyChannelReadyHandler so structured-concurrency cancellation is no longer swallowed; AGENTS.md is updated to document the rule and its withTimeout exception.
  • Tests cover all new code paths: null fundingTxo, stale/expired entry skipping, txid+vout match and no-match, vout-only mismatch, cache short-circuit, refresh failure fallback, and transient-failure retry.

Confidence Score: 5/5

Safe to merge — the fix is narrowly scoped to replacing a weak heuristic match with an exact funding-outpoint comparison, and all new branches are covered by unit tests.

The logic change in getCjitEntry is straightforward and well-tested: null fundingTxo returns early, exact txid+vout comparison replaces the size/pubkey heuristic, and the refresh retry path correctly handles TimeoutCancellationException as retriable while re-throwing other CancellationExceptions. The only finding is a 1-second superfluous delay after the last retry before returning the cached fallback — a minor inefficiency with no correctness impact.

No files require special attention; BlocktankRepo.kt carries the main logic change and is well-covered by the new tests.

Important Files Changed

Filename Overview
app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Core fix: getCjitEntry now matches by fundingTx id+vout instead of channel size+LSP pubkey; refreshCjitEntries adds retry logic with correct CancellationException/TimeoutCancellationException handling per AGENTS.md; minor: unnecessary delay fires after last retry before falling back to cache.
app/src/main/java/to/bitkit/ext/Coroutines.kt Adds runSuspendCatching — a correct coroutine-aware variant of runCatching that re-throws CancellationException while wrapping all other Throwables in Result.failure.
app/src/main/java/to/bitkit/domain/commands/NotifyChannelReadyHandler.kt Switches runCatching → runSuspendCatching and updates matching return labels; structured concurrency now preserved correctly in this handler.
app/src/test/java/to/bitkit/repositories/BlocktankRepoTest.kt Comprehensive new tests: null fundingTxo, stale unpaid entry not matched, txid+vout match/no-match, vout-only mismatch, no server refresh when no pending CJIT, expired entry skips refresh, cached hit short-circuits, refresh failure fallback, and transient-failure retry — solid coverage of the new logic.
app/src/test/java/to/bitkit/ext/CoroutinesTest.kt Three unit tests covering success, regular exception wrapping, and CancellationException re-throw for the new runSuspendCatching utility.
AGENTS.md Documents the new runSuspendCatching rule and its TimeoutCancellationException exception pattern, keeping the coding guidelines in sync with the implementation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ChannelReady event] --> B[NotifyChannelReadyHandler.invoke]
    B --> C[lightningRepo.getChannels — find by channelId]
    C -->|not found| D[Return Skip → Spending Balance Ready shown]
    C -->|found| E[blocktankRepo.getCjitEntry]
    E --> F{channel.fundingTxo == null?}
    F -->|yes| D
    F -->|no| G{Cached entry matches fundingTxo?}
    G -->|yes| M[Return IcJitEntry]
    G -->|no| H{hasPendingCjit in cache?}
    H -->|no| D
    H -->|yes| I[refreshCjitEntries — up to 3 attempts]
    I --> J{Fetch succeeds?}
    J -->|yes| K{Fetched list matches fundingTxo?}
    J -->|no — timeout/network| L{Last attempt?}
    L -->|no| I
    L -->|yes| N[Return cached list]
    N --> K
    K -->|no match| D
    K -->|match| M
    M --> O[activityRepo.insertActivityFromCjit]
    O -->|inserted| P[Return ShowSheet / ShowNotification]
    O -->|duplicate| Q[Return Duplicate]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[ChannelReady event] --> B[NotifyChannelReadyHandler.invoke]
    B --> C[lightningRepo.getChannels — find by channelId]
    C -->|not found| D[Return Skip → Spending Balance Ready shown]
    C -->|found| E[blocktankRepo.getCjitEntry]
    E --> F{channel.fundingTxo == null?}
    F -->|yes| D
    F -->|no| G{Cached entry matches fundingTxo?}
    G -->|yes| M[Return IcJitEntry]
    G -->|no| H{hasPendingCjit in cache?}
    H -->|no| D
    H -->|yes| I[refreshCjitEntries — up to 3 attempts]
    I --> J{Fetch succeeds?}
    J -->|yes| K{Fetched list matches fundingTxo?}
    J -->|no — timeout/network| L{Last attempt?}
    L -->|no| I
    L -->|yes| N[Return cached list]
    N --> K
    K -->|no match| D
    K -->|match| M
    M --> O[activityRepo.insertActivityFromCjit]
    O -->|inserted| P[Return ShowSheet / ShowNotification]
    O -->|duplicate| Q[Return Duplicate]
Loading

Reviews (5): Last reviewed commit: "fix: refresh cjit on empty cache" | Re-trigger Greptile

Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6b143259f3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
@jvsena42 jvsena42 marked this pull request as draft June 18, 2026 12:39
auto-merge was automatically disabled June 18, 2026 12:39

Pull request was converted to draft

@jvsena42

This comment was marked as resolved.

@jvsena42 jvsena42 marked this pull request as ready for review June 18, 2026 13:15

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae7baa7b7d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
@jvsena42 jvsena42 marked this pull request as draft June 18, 2026 13:24
@jvsena42 jvsena42 marked this pull request as ready for review June 18, 2026 13:42

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a884da4459

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
@jvsena42

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 85d27e6d75

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
jvsena42 added 2 commits June 18, 2026 12:02
… to the same wallet into one funding transaction while two CJIT invoices are pending, so their entries share a txid and differ only by vout
@jvsena42 jvsena42 requested a review from ovitrif June 18, 2026 16:39
ovitrif

This comment was marked as resolved.

@jvsena42 jvsena42 marked this pull request as draft June 19, 2026 11:54
@jvsena42

This comment was marked as resolved.

@jvsena42 jvsena42 marked this pull request as ready for review June 19, 2026 13:13
@jvsena42

Copy link
Copy Markdown
Member Author

Videos updated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6fceabe494

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt
Comment thread app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt Outdated
@jvsena42 jvsena42 marked this pull request as draft June 19, 2026 14:41
@jvsena42 jvsena42 marked this pull request as ready for review June 19, 2026 16:39

@ovitrif ovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utAck

@ovitrif ovitrif merged commit e156d8d into master Jun 19, 2026
17 checks passed
@ovitrif ovitrif deleted the fix/cjit-channel-false-match branch June 19, 2026 17:22
Sign up for free to 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.

2 participants