Skip to content

fix: notify on-chain receives that skip mempool#588

Open
CypherPoet wants to merge 5 commits into
synonymdev:masterfrom
CypherPoet:fix/onchain-confirmed-received-sheet
Open

fix: notify on-chain receives that skip mempool#588
CypherPoet wants to merge 5 commits into
synonymdev:masterfrom
CypherPoet:fix/onchain-confirmed-received-sheet

Conversation

@CypherPoet

@CypherPoet CypherPoet commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #455

Description

This PR fixes the missing "received" notification for on-chain transactions that confirm before the wallet ever sees them unconfirmed.

LDK Node fires onchainTransactionReceived when a transaction is first seen in the mempool, and onchainTransactionConfirmed when it confirms. The received sheet was only wired to the first event, so a transaction that goes straight to confirmed (a block is mined in the window between broadcast and the next sync) updated the balance and activity list but never showed the "Received Bitcoin" sheet. It is reliably reproducible on regtest, and theoretically possible on mainnet when the app is backgrounded or offline during that window.

Both the received and confirmed handlers now run the same check-and-show flow, so the notification appears for a new incoming transaction whether it was first seen in the mempool or arrived already confirmed. The existing seen-tracking means a transaction already announced on receive is not shown a second time when it later confirms.

Same issue as synonymdev/bitkit-android#797.

Linked Issues/Tasks

#455
Related: synonymdev/bitkit-android#797

Screenshot / Video

bitkit-455-before-after.mp4

Verified on regtest by depositing on-chain and mining one block immediately, so the transaction goes straight to confirmed. App-log counts for the identical repro:

build received events confirmed events received sheet shown
master (before) 0 1 0
this PR (after) 0 1 1

Zero received events on both runs confirms the transaction skipped the mempool, so the difference is purely the fix.

QA Notes

Manual Tests

  • 1. New regtest wallet → Dev Settings → Blocktank Regtest → Deposit → Mine Blocks (1) before the next sync: Received Bitcoin sheet appears.
  • 2. regression: Deposit → wait for the app to show the tx as unconfirmed → Mine Blocks (1): sheet shows once on receive and does not reappear on confirm.
  • 3. regression: Send on-chain → Mine Blocks (1): no Received sheet (outgoing, negative amount).
  • 4. regression: Channel open/close or same-value RBF: still no Received sheet. Not driven live; covered by the unchanged shouldShowReceivedSheet transfer/channel filters that the receive path already exercised.

Automated Checks

  • Built for iOS Simulator (Debug) locally: BUILD SUCCEEDED, compiles clean with no new warnings.
  • Verified on regtest via app logs: straight-to-confirmed shows the sheet once (test 1), a mempool-first receive shows it exactly once with no duplicate on confirm (test 2), and an outgoing send shows nothing (test 3). No unit coverage exists for handleLdkNodeEvent (LDK Event types plus shared service singletons), so verification is the manual regtest repro.
  • CI: standard build/test checks run by the PR bot.

When a transaction is confirmed before the wallet sees it unconfirmed, only onchainTransactionConfirmed fires. The received sheet was wired solely to onchainTransactionReceived, so straight-to-confirmed receives showed no notification. Both handlers now share one check-and-show helper. Fixes synonymdev#455.

@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: 3df9c525b9

ℹ️ 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 Bitkit/ViewModels/AppViewModel.swift
@ovitrif ovitrif added this to the 2.4.0 milestone Jun 8, 2026
Routing both onchainTransactionReceived and onchainTransactionConfirmed through the shared presenter means two tasks can run for one txid. The seen-check and mark were not atomic across awaits, so both events could present the sheet. Reserve the txid synchronously on the MainActor before any await so only the first event presents it. Addresses the PR synonymdev#588 review.
@ovitrif

ovitrif commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Hint: As a general note, we expect PR authors to Resolve the bot comments conversation thread after addressing them, via either GitHub web UI or directly via AI agents 😉.

I know some teams might get some members flamey over this, not the case with us.

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Got failure from the e2e test. After CPFP boost and subsequent restoration of the wallet we got the notification of previously received transaction in UI, pls see recording:

boost_-_Boost_boost_1_-_Can_do_CPFP-2026-06-10T21-22-29-359Z.mp4

Attaching also all artifacts that include simulator logs.
e2e-artifacts_e2e_1528.zip

On a wallet restore the activity store is rebuilt without seenAt, so the
initial on-chain sync replays onchainTransactionConfirmed for historical
receives. The shared presenter then showed the "Received" sheet for an old
transaction, which covered the activity list and timed out the CPFP restore
e2e. Set a pendingRestoreActivitySeen flag on the restore success screen, have
the presenter bail while it is set, and on the first post-restore on-chain
syncCompleted mark all unseen activities as seen and clear the flag. New
straight-to-confirmed receives still notify once the flag clears, so synonymdev#455 stays
fixed. Addresses the PR synonymdev#588 review.
@CypherPoet

Copy link
Copy Markdown
Contributor Author

Got failure from the e2e test. After CPFP boost and subsequent restoration of the wallet we got the notification of previously received transaction in UI, pls see recording:

boost_-Boost_boost_1-_Can_do_CPFP-2026-06-10T21-22-29-359Z.mp4
Attaching also all artifacts that include simulator logs. e2e-artifacts_e2e_1528.zip

@piotr-iohk I did some more digging on this, and it definitely seems to be an issue.

Root cause: on a wallet restore the activity store is rebuilt with no seenAt timestamps. During the
initial on-chain sync, LDK replays onchainTransactionConfirmed for historical (already received)
transactions. The new shared presenter then sees a positive amount, an unseen activity, and
shouldShowReceivedSheet == true, so it pops the "Received" sheet for an old transaction. That sheet
covered the activity list, which is why @boost_1 - Can do CPFP timed out after the restore step. A
normal launch was never affected (persisted seenAt already marks historical transactions as seen), and
migration restores already call markAllUnseenActivitiesAsSeen() on sync completion. Standard seed
restore had no equivalent.

Fix: a short-lived suppression flag that mirrors the existing migration handling, scoped to seed restore.

  • Set pendingRestoreActivitySeen when the user taps Get Started on the restore success screen.
  • While it is set, the received-sheet presenter returns early, so replayed historical confirmations do
    not notify.
  • On the first post-restore on-chain syncCompleted, mark all unseen activities as seen and clear the flag.

After the flag clears, genuinely new straight-to-confirmed receives notify again, so #455 stays fixed.

Verified on regtest:

  • Receive + confirm 100k, back up, wipe, restore: the historical receive lands in the activity list with
    no "Received" sheet, and the list is reachable (repro of the e2e failure, now passing).
  • A new deposit after restore still shows the "Received" sheet once (flag cleared correctly).
  • [Bug]: no received transaction notification when tx confirms without being seen in mempool #455 still holds: a new straight-to-confirmed receive notifies; mempool-first receives notify once and
    not again on confirmation.

The @boost_1 e2e should pass now.

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.

[Bug]: no received transaction notification when tx confirms without being seen in mempool

3 participants