Skip to content

Add shared block explorer presets#795

Merged
praveenperera merged 18 commits into
masterfrom
other-mempools
Jun 25, 2026
Merged

Add shared block explorer presets#795
praveenperera merged 18 commits into
masterfrom
other-mempools

Conversation

@praveenperera

@praveenperera praveenperera commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add Rust-owned block explorer preset options for mempool.guide, Bull Bitcoin mempool, Blockstream, Custom, and the default mempool.space explorer
  • Expose the preset list and selected option through UniFFI so iOS and Android share the same explorer catalog and selection behavior
  • Add settings UI copy explaining block explorers and show preset options before the custom URL/template editor

Validation

  • just fmt
  • cargo test block_explorer --lib
  • just clippy
  • just build-ios
  • just build-android
  • just compile-ios
  • just compile-android
  • just lint-android
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added selectable block explorer options, including custom URL/template support, with clearer save/reset flows and success feedback.
    • Improved block explorer URL handling across the app for more reliable previews and matching.
    • Enabled local network access on iOS for connecting to explorers and nodes.
  • Bug Fixes

    • Prevented duplicate updates when reselecting the same node preset.
    • Improved network request reliability in CI by reducing Cargo transport issues.
  • UI Improvements

    • Updated settings screens to better separate preset options from custom explorer input.
    • Simplified the block explorer entry in General settings.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a9e7e86d-dc6c-4dd2-8e4c-48dd193bdc5f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch other-mempools

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.

@praveenperera praveenperera marked this pull request as ready for review June 23, 2026 15:53
@greptile-apps

greptile-apps Bot commented Jun 23, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a curated list of block explorer presets (mempool.space, mempool.guide, Bull Bitcoin, Blockstream, Custom) shared across iOS and Android via UniFFI. It also refactors the template parsing into a dedicated module, adds scheme inference for local/IP addresses, and updates the settings UI to show a picker before the custom URL editor.

  • Rust core: BlockExplorerOption enum with preset definitions, matching_stored_template for round-tripping selections, set_block_explorer_option for saving presets, and all_block_explorer_options() exported via UniFFI.
  • Template module: Extracted and enhanced with domain validation, .local/IP scheme inference, and improved known-host matching; PREVIEW_TXID updated to the genesis coinbase transaction.
  • iOS/Android UI: Settings screens now show a radio-style preset list followed by the custom URL editor (only visible when Custom is selected); preset saves are synchronous while custom URL saves are async with a loading indicator (Android) or success popup (iOS).

Confidence Score: 5/5

Safe to merge; the two findings are cosmetic UX nits that don't affect data integrity or stored state.

The Rust core changes are well-tested, the UniFFI surface is consistent with existing patterns, and no stored data is at risk. The two flagged issues — unconditional input clearing when re-tapping an already-selected Custom option, and synchronous DB calls in savePreset on the main thread — are both minor quality concerns that don't cause incorrect persisted state or crashes.

The select(.custom) path in both BlockExplorerSettingsView.swift and BlockExplorerSettingsScreen.kt clears the text field even when Custom is already the active selection.

Important Files Changed

Filename Overview
rust/src/custom_block_explorer.rs Introduces BlockExplorerOption enum with preset definitions, matching logic, and UniFFI-exported helpers; old template code moved to template.rs. Logic is sound and well-tested.
rust/src/custom_block_explorer/template.rs New module holding the template parsing logic refactored from the old custom_block_explorer.rs, with enhanced host validation, scheme inference for local/IP inputs, and a comprehensive test suite.
rust/src/database/global_config.rs Adds selected_block_explorer_option and set_block_explorer_option, removes effective_block_explorer_host; preset arm uses expect() on base_url (pre-existing concern noted in prior review threads).
ios/Cove/Flows/SettingsFlow/BlockExplorerSettingsView.swift Replaces free-text-only editor with a preset picker plus a conditional Custom section; select(.custom) unconditionally clears input even when Custom is already selected, discarding unsaved input.
android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/BlockExplorerSettingsScreen.kt Adds preset list UI and async save; savePreset() calls DB operations on the main thread while save() correctly uses withContext(Dispatchers.IO), creating an inconsistency.
ios/Cove/Info.plist Adds NSAllowsLocalNetworking and NSLocalNetworkUsageDescription to support custom explorers on .local hostnames and local IP addresses.
.github/workflows/ci.yml Adds CARGO_HTTP_MULTIPLEXING=false and CARGO_NET_RETRY=10 env vars to improve reliability of cargo dependency fetching in CI.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Settings UI (iOS/Android)
    participant Rust as Rust (UniFFI)
    participant DB as Database

    Note over UI,DB: Selecting a preset (non-Custom)
    UI->>Rust: setBlockExplorerOption(network, option)
    Rust->>DB: clear OR set custom template
    DB-->>Rust: ok
    Rust-->>UI: normalized template string?
    UI->>Rust: effectiveBlockExplorerPreview(network)
    Rust-->>UI: preview URL
    UI->>Rust: selectedBlockExplorerOption(network)
    Rust-->>UI: BlockExplorerOption

    Note over UI,DB: Selecting Custom (local state only, no DB write)
    UI->>UI: "selectedOption = .custom, input = """

    Note over UI,DB: Saving a custom URL
    UI->>Rust: setCustomBlockExplorer(network, input)
    Rust->>DB: store template
    DB-->>Rust: ok
    Rust-->>UI: normalized template
    UI->>Rust: effectiveBlockExplorerPreview(network)
    Rust-->>UI: preview URL
    UI->>Rust: selectedBlockExplorerOption(network)
    Rust-->>UI: BlockExplorerOption (.custom)
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"}}}%%
sequenceDiagram
    participant UI as Settings UI (iOS/Android)
    participant Rust as Rust (UniFFI)
    participant DB as Database

    Note over UI,DB: Selecting a preset (non-Custom)
    UI->>Rust: setBlockExplorerOption(network, option)
    Rust->>DB: clear OR set custom template
    DB-->>Rust: ok
    Rust-->>UI: normalized template string?
    UI->>Rust: effectiveBlockExplorerPreview(network)
    Rust-->>UI: preview URL
    UI->>Rust: selectedBlockExplorerOption(network)
    Rust-->>UI: BlockExplorerOption

    Note over UI,DB: Selecting Custom (local state only, no DB write)
    UI->>UI: "selectedOption = .custom, input = """

    Note over UI,DB: Saving a custom URL
    UI->>Rust: setCustomBlockExplorer(network, input)
    Rust->>DB: store template
    DB-->>Rust: ok
    Rust-->>UI: normalized template
    UI->>Rust: effectiveBlockExplorerPreview(network)
    Rust-->>UI: preview URL
    UI->>Rust: selectedBlockExplorerOption(network)
    Rust-->>UI: BlockExplorerOption (.custom)
Loading

Reviews (2): Last reviewed commit: "Match preset block explorers explicitly" | Re-trigger Greptile

Comment thread rust/src/custom_block_explorer.rs
Comment thread rust/src/database/global_config.rs
@praveenperera praveenperera force-pushed the other-mempools branch 3 times, most recently from b345da9 to de9d0ea Compare June 24, 2026 16:34

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

Actionable comments posted: 6

🤖 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
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/BlockExplorerSettingsScreen.kt`:
- Around line 131-134: The block explorer persistence call in
BlockExplorerSettingsScreen should stay on the caller coroutine thread instead
of hopping to Dispatchers.IO. Update the logic around
config.setCustomBlockExplorer inside the relevant save flow to invoke the Rust
FFI call directly, and keep the surrounding coroutine handling unchanged so the
function still captures the returned result normally.
- Around line 170-176: The selectOption function in BlockExplorerSettingsScreen
should not reset the custom explorer input when CUSTOM is tapped while it is
already selected. Update the BlockExplorerOption.CUSTOM branch in selectOption
to return early if selectedOption is already CUSTOM, so the existing input and
preview remain unchanged; otherwise keep the existing behavior for switching to
CUSTOM.

In
`@android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/NodeSettingsScreen.kt`:
- Around line 136-138: The early return in the node selection handler is
comparing only selectedNodeName, which can incorrectly block a real change when
a custom node shares a name with a preset. Update the guard in
NodeSettingsScreen’s selection logic to compare the actual selected node state,
using both selectedNodeName and selectedNodeSelection (or the full selection
identity) before returning, so a preset can still be selected when the name
matches but the selection type differs.

In `@ios/Cove/Flows/SettingsFlow/BlockExplorerSettingsView.swift`:
- Around line 123-128: The select(_:) handler in BlockExplorerSettingsView is
clearing the custom editor even when .custom is already selected. Update the
BlockExplorerOption switching logic to return early if the tapped option matches
the current selectedOption, and only reset input/updatePreview when changing
into the custom option from a different selection. Keep the fix localized to
select(_:) so saved custom templates are preserved when re-tapping the Custom
row.

In `@rust/src/custom_block_explorer.rs`:
- Around line 73-80: The default label returned by as_display_name is
provider-specific, but MempoolSpace is only the default option and may not map
to mempool.space on all networks. Update the MempoolSpace match arm in
custom_block_explorer::as_display_name to use a provider-neutral label such as
“Default explorer”, or make it network-aware if the display name should reflect
the active template.

In `@rust/src/custom_block_explorer/template.rs`:
- Around line 326-333: The known_host_network_prefix mapping in template.rs only
handles mempool.space and mutinynet.com, so BlockExplorerOption::base_url() ->
from_base_url() can drop the network segment for new multi-network presets like
Blockstream on Testnet. Extend the prefix table to cover provider-specific
non-Bitcoin network prefixes for the new presets, or make unsupported
preset/network combinations fail explicitly in the same flow, and add tests that
verify non-Bitcoin canonicalization for the affected BlockExplorerOption
variants.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cf6fb8f8-8d01-45f8-bdc8-04252ce7ece2

📥 Commits

Reviewing files that changed from the base of the PR and between b0ce973 and b24630a.

⛔ Files ignored due to path filters (2)
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt is excluded by !android/app/src/main/java/org/bitcoinppl/cove_core/**
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**, !ios/CoveCore/Sources/CoveCore/generated/**
📒 Files selected for processing (12)
  • .github/workflows/ci.yml
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/BlockExplorerSettingsScreen.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/MainSettingsScreen.kt
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/NodeSettingsScreen.kt
  • android/app/src/main/res/values/strings.xml
  • ios/Cove/Flows/SettingsFlow/BlockExplorerSettingsView.swift
  • ios/Cove/Flows/SettingsFlow/MainSettingsScreen.swift
  • ios/Cove/Info.plist
  • ios/Cove/Views/MiddlePopupView.swift
  • rust/src/custom_block_explorer.rs
  • rust/src/custom_block_explorer/template.rs
  • rust/src/database/global_config.rs
💤 Files with no reviewable changes (1)
  • android/app/src/main/java/org/bitcoinppl/cove/flows/SettingsFlow/MainSettingsScreen.kt

Comment thread ios/Cove/Flows/SettingsFlow/BlockExplorerSettingsView.swift
Comment thread rust/src/custom_block_explorer.rs
Comment thread rust/src/custom_block_explorer/template.rs
praveenperera and others added 18 commits June 25, 2026 10:28
Add top-level Cargo environment variables to the CI workflow: CARGO_HTTP_MULTIPLEXING=false and CARGO_NET_RETRY=10. These apply to all jobs to disable HTTP multiplexing and increase retry attempts for Cargo network operations, reducing intermittent CI failures due to registry/network issues.
Show a heading above the block explorer description on both platforms for clarity. Android: wrap the description in a Column and add stringResource(R.string.title_settings_block_explorer) with bodyMedium styling and spacing (BlockExplorerSettingsScreen.kt). iOS: add a VStack containing a "Block Explorer" subheadline (semibold) above the explanatory footnote and adjust spacing (BlockExplorerSettingsView.swift).
Resolve known explorer domains and /tx paths to their canonical templates before the generic fallback. Keep successful custom saves on the Custom row so the normalized template remains visible.
Add async save-state feedback in Android and iOS block explorer settings and default scheme handling for local and IP hosts in URL parsing so custom block explorers save and parse correctly.
Split custom explorer template parsing and validation into a

a dedicated module so public option logic stays focused. Keep

template behavior intact while centralizing placeholder

normalization, URL matching, and stored-template fallback
Android: avoid resetting custom node fields when re-selecting the currently selected preset node by returning early if the node name is unchanged.

iOS: add client-side validation and user feedback when saving custom block explorer URLs. Introduce showInvalidUrlAlert and an alert UI, call previewCustomBlockExplorer before saving to catch errors early, simplify isSaving handling with defer, and show success popup on save. Validation errors now surface via an alert.

Rust: strengthen URL/host validation for custom block explorer templates. Add validate_host, validate_domain_host, and is_valid_domain_label to enforce domain label rules, allow localhost and numeric IPs, and reject invalid TLDs; update scheme preference logic to treat localhost and .local appropriately. Extend tests to cover local, IP, and invalid domain cases.
Add a pre-save network check for custom block explorer URLs

by requesting a known transaction URL first, then persist only on success and

present loading/success/error feedback while the check runs
Remove the specialized effectiveBlockExplorerHost API and associated UniFFI bindings/checksum entries, and centralize block-explorer validation in the core. UI changes (Android & iOS) drop the async URL-checking task and related helpers, instead relying on config.setCustomBlockExplorer/preview to validate and produce normalized values; preview and validationError handling were simplified to surface errors while typing. Rust code cleans up documentation comments and removes the GlobalConfigTable host-extraction helper. Note: UniFFI checksum constants were updated — clean/rebuild native bindings after applying this change.
Remove the inline validationError state and its on-screen text. Introduce showUpdateFailedAlert and an alert UI for update failures, and wire error paths to present this alert (while keeping the existing invalid-URL alert). Update error handling in save/update/clear flows to set the new alert flag instead of storing validationError.
Replace the catch-all '_' arm with explicit arms for BlockExplorerOption::MempoolGuide, ::BullBitcoin and ::Blockstream. These variants now use their preset base_url and are registered via set_custom_block_explorer, making the match handling clearer and avoiding a generic wildcard branch.
Preserve custom block explorer input when reselecting the custom option, keep Rust FFI persistence on the caller coroutine, and avoid blocking preset node changes when a custom node shares the same name.

Store preset block explorer templates through their network-aware canonical form so non-Bitcoin paths are preserved and unsupported preset networks fail explicitly.
@praveenperera praveenperera merged commit a0e31a3 into master Jun 25, 2026
9 checks passed
@praveenperera praveenperera deleted the other-mempools branch June 25, 2026 19:49
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.

1 participant