Skip to content

fix: resolve provider init and node-switch restore connectivity races - #631

Merged
AndreaDiazCorreia merged 2 commits into
mainfrom
fix/order-repository-init-race
Jun 24, 2026
Merged

fix: resolve provider init and node-switch restore connectivity races#631
AndreaDiazCorreia merged 2 commits into
mainfrom
fix/order-repository-init-race

Conversation

@AndreaDiazCorreia

@AndreaDiazCorreia AndreaDiazCorreia commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary

Fixes two pre-existing race conditions that surface after the Riverpod 3.x rollback (#628), both caused by code that the revert does not touch:

  1. Exception: Nostr is not initialized. Call init() first. during app start, logged as "Failed to init mostro instance listener".
  2. TimeoutException: Stage RestoreStage.gettingRestoreData timed out after 10s when switching Mostro nodes.

Neither is introduced by the revert; the Riverpod 2.x timing change merely exposes them.

Root causes

1. Order repository init race

OpenOrdersRepository's constructor eagerly calls subscribeToEvents(), which throws when NostrService is not yet initialized. The transport Phase A listener (SubscriptionManager._initMostroInstanceListener) forces the first build of orderRepositoryProvider during SubscriptionManager construction, which can run before init() completes. The thrown error is cached on the provider, poisoning every later read of the order repository.

2. Node-switch restore timeout

Since the move to bootstrap relay discovery (#610), no relays are seeded and the selected node's relays are rediscovered asynchronously via kind 10002. On node switch, initRestoreProcess() sends the restore request immediately, while the
new node's relays take up to ~5s (periodic resync) plus discovery to connect, so the request races connectivity and times out before any relay can route it.

Changes

  • OpenOrdersRepository._subscribeToOrders(): defer the subscription with a bounded retry when NostrService is not initialized, instead of throwing and poisoning the provider.
  • OpenOrdersRepository.updateSettings(): reset _mostroInstance on instance change so stale node info is not reported for the new instance.
  • RestoreService: add _waitForNodeConnectivity(), called before sending the restore request. It engages the bootstrap relays immediately (instead of waiting for the periodic watchdog) and waits for the node's info event (kind 38385) within the discovery window, falling back to a best-effort attempt with a live-relay floor.

Verification

  • flutter analyze: no issues.
  • flutter test: all tests pass (473).
  • Runtime: confirm node switching no longer times out for default and custom
    nodes, and the order book loads cleanly on cold start.

Notes

Summary by CodeRabbit

Release Notes

  • New Features

    • Improved restore mode state management and progress flow.
    • Enhanced navigation notification indicators for chats and order book.
  • Bug Fixes

    • Improved session recovery by waiting for node connectivity before starting restores.
    • Improved startup reliability by delaying order subscriptions until initialization is ready (with bounded retries).
    • Simplified restore message decoding to a single gift-wrap path to reduce transport-related edge cases.
  • Refactor

    • Streamlined message signing/wrapping and unified wrapping behavior across ordering and disputes.
  • Chores

    • Updated Flutter/Gradle/Kotlin toolchain versions; upgraded dependencies and icon packages.
    • Removed obsolete NIP-44/NIP-59 v2 transport test coverage; cleaned up unused/legacy Riverpod imports.
    • Updated payment methods by removing the MWK currency entry.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@AndreaDiazCorreia, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 52 minutes and 12 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4f63fcd-4a93-481d-aa8d-6417c3b61ef1

📥 Commits

Reviewing files that changed from the base of the PR and between 82c5612 and f3ab613.

📒 Files selected for processing (3)
  • lib/data/repositories/open_orders_repository.dart
  • lib/features/relays/relays_notifier.dart
  • lib/features/restore/restore_manager.dart

Walkthrough

This PR downgrades the Flutter SDK (~3.44 → ~3.32), Android build toolchain (Gradle 8.14→8.9, AGP 8.11→8.6, Kotlin 2.2→2.1), and Riverpod from 3.3.2 to 2.6.1 while replacing lucide_icons_flutter with lucide_icons. Concurrently, wrapNip44/wrapForTransport are removed from MostroMessage in favor of the unified wrap(); the restore flow is narrowed to kind-1059 only with a new node-connectivity polling gate; OpenOrdersRepository gains an initialization retry timer; and bottom nav exposes notification count providers. All affected tests are rewired to use MockRef stubs instead of ProviderContainer overrides.

Changes

Toolchain and dependency downgrade

Layer / File(s) Summary
Flutter SDK and Android build toolchain
.fvmrc, .github/workflows/*, android/gradle/wrapper/gradle-wrapper.properties, android/settings.gradle, android/app/build.gradle
Flutter SDK pinned to ~3.32.x in fvmrc and all CI/release workflows; Gradle wrapper downgraded from 8.14.3 to 8.9; AGP from 8.11.1 to 8.6.0; Kotlin from 2.2.20 to 2.1.0; kotlinOptions.jvmTarget moved inside android {} block; migration flags removed from gradle.properties.
Riverpod 2.x and lucide_icons dependency swap
pubspec.yaml, lib/services/event_bus.dart, lib/features/order/providers/order_notifier_provider.dart
flutter_riverpod and hooks_riverpod downgraded from ^3.3.2 to ^2.6.1; lucide_icons_flutter replaced with lucide_icons ^0.257.0; AutoDisposeProvider and AutoDisposeStateNotifierProvider constructor syntax adopted.
Mass legacy Riverpod import cleanup
lib/features/..., lib/shared/..., lib/services/exchange_service.dart
Removes flutter_riverpod/legacy.dart import from ~35 notifiers, providers, and service files; switches to flutter_riverpod/flutter_riverpod.dart; lucide_icons_flutter import replaced in all widget files.

Transport simplification, restore improvements, and functional fixes

Layer / File(s) Summary
MostroMessage transport API simplification
lib/data/models/mostro_message.dart
Removes version parameters from toJson/sign/serialize; sign now computes SHA-256 of UTF-8 wrapper JSON directly; wrapNip44 and wrapForTransport methods removed; transport.dart import removed.
Call sites migrated to unified wrap()
lib/data/repositories/dispute_repository.dart, lib/services/mostro_service.dart, lib/features/restore/restore_manager.dart
DisputeRepository.createDispute, MostroService.publishOrder, and all three restore request wrapping calls switch from wrapForTransport to wrap(); protocol-version routing and transport-kind log messages removed.
Restore flow: kind-1059 only and node-connectivity gating
lib/features/restore/restore_manager.dart, lib/features/restore/restore_mode_provider.dart, docs/architecture/SESSION_RECOVERY_ARCHITECTURE.md, docs/architecture/TRANSPORT_V2_MIGRATION.md
Adds _waitForNodeConnectivity() that polls for node instance pubkey before restore starts; narrows _createTempSubscription to kind-1059 only; _extractRestoreData, _extractOrdersDetails, _extractLastTradeIndex now unwrap via event.mostroUnWrap instead of the removed decodeRestoreMessage; isRestoringProvider StateProvider<bool> added; docs updated to reflect kind-1059-only decode path.
OpenOrdersRepository initialization retry
lib/data/repositories/open_orders_repository.dart
Adds _initRetryTimer, _initRetryInterval, and _maxInitRetries; _subscribeToOrders defers via _scheduleSubscribeWhenReady if NostrService is not yet initialized; dispose cancels the timer; updateSettings clears _mostroInstance to prevent stale node info.
Bottom nav notification counts and data cleanup
lib/shared/widgets/bottom_nav_bar.dart, assets/data/payment_methods.json
Adds chatCountProvider and orderBookNotificationCountProvider StateProvider<int> and wires them into _buildNavItem for dot indicators; removes MWK currency entry.
Test wiring: MockRef replaces ProviderContainer
test/mocks.dart, test/features/mostro/*, test/notifiers/*, test/services/mostro_service_test.dart
Adds Ref and ProviderSubscription to @GenerateMocks; removes createTestRef helper; all affected test setUp methods switch from ProviderContainer overrides to direct MockRef stubs; mostro_message_nip44_test.dart and restore_decode_test.dart deleted.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • MostroP2P/mobile#624: This PR directly reverses the Phase-B transport-v2 work from #624 by removing wrapNip44/wrapForTransport and their versioned toJson/sign/serialize overloads across MostroMessage, DisputeRepository, and restore wrapping.
  • MostroP2P/mobile#613: Shares the same Riverpod migration theme; both PRs update flutter_riverpod imports from legacy to non-legacy entry points across notifiers and providers.
  • MostroP2P/mobile#440: Both PRs modify initRestoreProcess in restore_manager.dart—this PR adds node-connectivity gating before restore subscription creation, directly extending the restore lifecycle touched by #440.

Suggested reviewers

  • grunch
  • BraCR10

🐇 Hop hop, the versions went down,
From 3.44 to a cosier town!
wrapNip44? Gone with a flick,
One wrap() to rule them all—slick!
Kind-1059 only, no branching today,
The rabbit says: simplified is the way! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main fixes: resolving provider initialization race conditions and node-switch restore connectivity issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/order-repository-init-race

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@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: a830acc9ac

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/services/mostro_service.dart
Comment thread lib/features/restore/restore_manager.dart
Comment thread .github/workflows/flutter.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/shared/widgets/bottom_nav_bar.dart (1)

8-9: 🎯 Functional Correctness | 🟡 Minor

Verify that notification counters are written to somewhere in the codebase.

The chatCountProvider and orderBookNotificationCountProvider are initialized to 0 but have no writers anywhere in the codebase—they remain dead counters that never trigger the notification dots (line 108). Additionally, orderBookNotificationCountProvider is wired to the myTrades nav item (index 1), not the order book item (index 0), suggesting either the name is misleading or the wiring is incorrect.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/shared/widgets/bottom_nav_bar.dart` around lines 8 - 9, The
chatCountProvider and orderBookNotificationCountProvider are initialized but
lack any writers in the codebase to update their values, making them dead code
that never triggers the notification dots at line 108. Additionally,
orderBookNotificationCountProvider is wired to the myTrades navigation item
(index 1) instead of the orderBook item (index 0), indicating either the
provider name is misleading or the wiring is incorrect. Add code that writes to
these providers whenever chat messages or relevant notifications are received
from your backend or data sources, and verify that the provider wiring in the
BottomNavigationBar construction matches the intended navigation items—either
rename orderBookNotificationCountProvider to reflect its actual use with
myTrades, or rewire it to the correct navigation index if the name is correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.fvmrc:
- Line 2: The Flutter SDK version in .fvmrc is pinned to 3.35.7 while CI
workflows (flutter.yml, desktop.yml, main.yml, and release.yml) use inconsistent
versions like 3.32.5 and 3.32.2, causing divergence between local development
and CI environments. Choose a single Flutter version and update the flutter
field in .fvmrc and all occurrences in the CI workflow files to use that same
version consistently across all configurations.

In `@lib/data/repositories/dispute_repository.dart`:
- Around line 55-57: The `wrap()` method call on `disputeMessage` at line 55 is
missing the `masterKey` and `keyIndex` parameters that are present in the
standard publish path. Add these missing parameters to the `wrap()` call to
ensure that identity and trade-index semantics are properly preserved for
non-full-privacy sessions. Include both parameters with their appropriate values
to align with how wrap is called elsewhere in the publish flow.

In `@lib/features/relays/relays_notifier.dart`:
- Line 691: The inline comment marked with "// 🔥 RESET COMPLETO: Limpiar todos
los relays y hacer sync fresco" is written in Spanish and violates the coding
guideline requiring all comments to be in English. Translate this comment to
English while preserving its meaning about performing a complete reset, cleaning
all relays, and performing a fresh synchronization.

---

Outside diff comments:
In `@lib/shared/widgets/bottom_nav_bar.dart`:
- Around line 8-9: The chatCountProvider and orderBookNotificationCountProvider
are initialized but lack any writers in the codebase to update their values,
making them dead code that never triggers the notification dots at line 108.
Additionally, orderBookNotificationCountProvider is wired to the myTrades
navigation item (index 1) instead of the orderBook item (index 0), indicating
either the provider name is misleading or the wiring is incorrect. Add code that
writes to these providers whenever chat messages or relevant notifications are
received from your backend or data sources, and verify that the provider wiring
in the BottomNavigationBar construction matches the intended navigation
items—either rename orderBookNotificationCountProvider to reflect its actual use
with myTrades, or rewire it to the correct navigation index if the name is
correct.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: da40a1bd-d05e-4cb1-b19d-7ba6eab7a6c0

📥 Commits

Reviewing files that changed from the base of the PR and between 0c3676d and a830acc.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (85)
  • .fvmrc
  • .github/workflows/desktop.yml
  • .github/workflows/flutter.yml
  • .github/workflows/main.yml
  • .github/workflows/release.yml
  • android/app/build.gradle
  • android/gradle.properties
  • android/gradle/wrapper/gradle-wrapper.properties
  • android/settings.gradle
  • assets/data/payment_methods.json
  • docs/architecture/SESSION_RECOVERY_ARCHITECTURE.md
  • docs/architecture/TRANSPORT_V2_MIGRATION.md
  • lib/data/models/mostro_message.dart
  • lib/data/repositories/dispute_repository.dart
  • lib/data/repositories/open_orders_repository.dart
  • lib/features/auth/notifiers/auth_notifier.dart
  • lib/features/auth/providers/auth_notifier_provider.dart
  • lib/features/chat/chat_room_provider.dart
  • lib/features/chat/notifiers/chat_room_notifier.dart
  • lib/features/chat/notifiers/chat_rooms_notifier.dart
  • lib/features/chat/providers/active_chat_screens_provider.dart
  • lib/features/chat/providers/chat_room_providers.dart
  • lib/features/chat/providers/chat_tab_provider.dart
  • lib/features/chat/widgets/chat_messages_list.dart
  • lib/features/community/providers/community_selector_provider.dart
  • lib/features/disputes/notifiers/dispute_chat_notifier.dart
  • lib/features/disputes/providers/dispute_read_status_provider.dart
  • lib/features/home/providers/home_order_providers.dart
  • lib/features/key_manager/key_management_screen.dart
  • lib/features/logs/logs_provider.dart
  • lib/features/mostro/mostro_instance_provider.dart
  • lib/features/mostro/mostro_nodes_notifier.dart
  • lib/features/mostro/mostro_nodes_provider.dart
  • lib/features/notifications/notifiers/notifications_notifier.dart
  • lib/features/notifications/providers/backup_reminder_provider.dart
  • lib/features/notifications/providers/notifications_provider.dart
  • lib/features/order/notifiers/abstract_mostro_notifier.dart
  • lib/features/order/providers/order_notifier_provider.dart
  • lib/features/order/providers/payment_methods_provider.dart
  • lib/features/relays/relays_notifier.dart
  • lib/features/relays/relays_provider.dart
  • lib/features/restore/restore_manager.dart
  • lib/features/restore/restore_mode_provider.dart
  • lib/features/restore/restore_progress_notifier.dart
  • lib/features/settings/about_screen.dart
  • lib/features/settings/notification_settings_screen.dart
  • lib/features/settings/settings_notifier.dart
  • lib/features/settings/settings_provider.dart
  • lib/features/settings/settings_screen.dart
  • lib/features/trades/providers/trades_provider.dart
  • lib/features/trades/widgets/status_filter_widget.dart
  • lib/features/walkthrough/providers/first_run_provider.dart
  • lib/features/wallet/providers/nwc_provider.dart
  • lib/features/wallet/screens/connect_wallet_screen.dart
  • lib/features/wallet/screens/wallet_settings_screen.dart
  • lib/features/wallet/widgets/wallet_balance_widget.dart
  • lib/features/wallet/widgets/wallet_status_card.dart
  • lib/services/event_bus.dart
  • lib/services/exchange_service.dart
  • lib/services/mostro_service.dart
  • lib/shared/notifiers/locale_notifier.dart
  • lib/shared/notifiers/navigation_notifier.dart
  • lib/shared/notifiers/session_notifier.dart
  • lib/shared/providers/drawer_provider.dart
  • lib/shared/providers/exchange_service_provider.dart
  • lib/shared/providers/navigation_notifier_provider.dart
  • lib/shared/providers/session_notifier_provider.dart
  • lib/shared/widgets/bottom_nav_bar.dart
  • lib/shared/widgets/custom_drawer_overlay.dart
  • lib/shared/widgets/ln_address_confirmation_widget.dart
  • lib/shared/widgets/nwc_connection_status_indicator.dart
  • lib/shared/widgets/nwc_invoice_widget.dart
  • lib/shared/widgets/nwc_notification_listener.dart
  • lib/shared/widgets/nwc_payment_receipt_widget.dart
  • lib/shared/widgets/nwc_payment_widget.dart
  • pubspec.yaml
  • test/data/mostro_message_nip44_test.dart
  • test/features/mostro/mostro_integration_test.dart
  • test/features/mostro/mostro_nodes_notifier_test.dart
  • test/features/mostro/mostro_nodes_performance_test.dart
  • test/features/restore/restore_decode_test.dart
  • test/mocks.dart
  • test/notifiers/add_order_notifier_test.dart
  • test/notifiers/take_order_notifier_test.dart
  • test/services/mostro_service_test.dart
💤 Files with no reviewable changes (25)
  • lib/features/order/providers/payment_methods_provider.dart
  • lib/features/settings/settings_notifier.dart
  • lib/features/notifications/notifiers/notifications_notifier.dart
  • lib/features/chat/chat_room_provider.dart
  • lib/features/chat/providers/chat_room_providers.dart
  • lib/features/notifications/providers/notifications_provider.dart
  • lib/features/wallet/providers/nwc_provider.dart
  • lib/shared/notifiers/session_notifier.dart
  • lib/features/home/providers/home_order_providers.dart
  • lib/features/order/notifiers/abstract_mostro_notifier.dart
  • lib/features/auth/providers/auth_notifier_provider.dart
  • lib/features/mostro/mostro_nodes_notifier.dart
  • lib/features/chat/notifiers/chat_rooms_notifier.dart
  • lib/services/exchange_service.dart
  • assets/data/payment_methods.json
  • lib/features/chat/notifiers/chat_room_notifier.dart
  • lib/features/logs/logs_provider.dart
  • android/gradle.properties
  • lib/features/community/providers/community_selector_provider.dart
  • test/features/restore/restore_decode_test.dart
  • lib/features/disputes/notifiers/dispute_chat_notifier.dart
  • lib/features/trades/providers/trades_provider.dart
  • lib/shared/providers/exchange_service_provider.dart
  • lib/features/walkthrough/providers/first_run_provider.dart
  • test/data/mostro_message_nip44_test.dart

Comment thread .fvmrc
Comment thread lib/data/repositories/dispute_repository.dart
Comment thread lib/features/relays/relays_notifier.dart Outdated
Catrya
Catrya previously approved these changes Jun 23, 2026

@Catrya Catrya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

tACK

AndreaDiazCorreia and others added 2 commits June 23, 2026 21:37
…ests

- Add _waitForNodeConnectivity to ensure the app is connected to the selected node before restore
- Engage bootstrap relays immediately and wait for kind 38385 info event to prove connectivity
- Fall back to best-effort attempt if info event not received within discovery window
- Add _initRetryTimer to OpenOrdersRepository to poll for NostrService readiness
- Defer order subscription until NostrService.isInitialized to avoid
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@AndreaDiazCorreia
AndreaDiazCorreia force-pushed the fix/order-repository-init-race branch from 82c5612 to f3ab613 Compare June 24, 2026 00:38

@ermeme ermeme 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.

Reviewed on the current head. Looks good to me — approved.

@AndreaDiazCorreia
AndreaDiazCorreia merged commit 738e5f2 into main Jun 24, 2026
2 checks passed
@AndreaDiazCorreia
AndreaDiazCorreia deleted the fix/order-repository-init-race branch June 24, 2026 00:45
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