Skip to content

refactor(platform-wallet): extract shared contact request logic and use tracing#3206

Draft
thepastaclaw wants to merge 3 commits intodashpay:v3.1-devfrom
thepastaclaw:feat/identity-discovery-scan
Draft

refactor(platform-wallet): extract shared contact request logic and use tracing#3206
thepastaclaw wants to merge 3 commits intodashpay:v3.1-devfrom
thepastaclaw:feat/identity-discovery-scan

Conversation

@thepastaclaw
Copy link
Contributor

@thepastaclaw thepastaclaw commented Mar 6, 2026

Summary

Follow-up refactor for #3188 (identity discovery scan). Addresses self-review findings:

  1. Extract duplicated contact request logicfetch_and_store_contact_requests() helper eliminates ~60 lines of copy-paste between identity_discovery.rs and matured_transactions.rs
  2. Replace eprintln! with tracing::warn! — proper structured logging for a library crate
  3. Name the magic number100DEFAULT_CONTACT_REQUEST_LIMIT
  4. Log silently-swallowed parse errors — parse failures in contact request documents now emit warnings instead of being silently ignored

Validation

  • cargo check
  • cargo clippy
  • cargo fmt --check
  • 9/9 existing tests pass ✅

Summary by CodeRabbit

  • New Features

    • Added identity discovery with gap-limit scanning to efficiently identify registered identities during wallet synchronization
    • Added support for fetching and storing associated contact requests alongside discovered identities
  • Improvements

    • Enhanced logging and diagnostics using improved tracing infrastructure for better visibility into wallet operations

QuantumExplorer and others added 2 commits March 5, 2026 14:20
Add DashSync-style identity discovery to PlatformWalletInfo that
scans consecutive DIP-13 authentication key indices and queries
Platform to find registered identities during wallet sync.

New methods:
- discover_identities: gap-limit scan using PublicKeyHash queries
- discover_identities_with_contacts: same + fetches DashPay contacts

Refactors shared key derivation and contact request parsing into
reusable modules used by both discovery and asset lock processing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…se tracing

- Extract duplicated contact request fetch+store loops from
  identity_discovery.rs and matured_transactions.rs into a shared
  fetch_and_store_contact_requests() helper method on PlatformWalletInfo
- Replace all eprintln! calls with tracing::warn! for proper library
  logging (add tracing dependency)
- Extract magic number 100 into DEFAULT_CONTACT_REQUEST_LIMIT constant
- Log silently-swallowed contact request parse errors instead of
  ignoring them (aids debugging malformed documents)
@thepastaclaw
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

Important

Review skipped

Draft detected.

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7fe4955b-0e9e-4635-943d-c12aa3a25c56

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
  • Post copyable unit tests in a comment

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 and usage tips.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main refactoring goals: extracting shared contact request logic and adopting structured logging via tracing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/rs-platform-wallet/src/platform_wallet_info/identity_discovery.rs`:
- Around line 82-89: The Err(e) arm currently increments consecutive_misses
(variable consecutive_misses) which treats query failures as empty slots;
instead do not count errors as misses—either propagate the error out from the
current function (replace the Err(e) branch with an early return/return Err(e)
or use the ? operator) or log and retry without modifying consecutive_misses;
keep the tracing::warn call but remove the consecutive_misses += 1 so query
failures don't stop the scan prematurely.
- Around line 68-76: The discovered list is being appended even when the
identity already exists; change the logic so you first check for existence using
identity_manager().identity(&identity_id) (to avoid cloning the entire
identities() map), and only call identity_manager_mut().add_identity(identity)?
and then discovered.push(identity_id) when the identity was actually added;
ensure discovered.push is moved inside that conditional that wraps
add_identity().

In
`@packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs`:
- Around line 82-83: The code in matured_transactions.rs currently hardcodes
identity_index = 0 when calling derive_identity_auth_key_hash(wallet,
self.network(), 0, 0), which prevents discovery of identities beyond the first
slot; change this to use the wallet's known identity candidate index or invoke
the gap-limit discovery flow instead of a fixed 0. Locate
derive_identity_auth_key_hash usage in matured_transactions.rs and replace the
literal 0 for identity_index with a value obtained from the wallet state (e.g.,
the candidate identity index accessor on the Wallet object) or call the new
discovery function (the gap-limit discovery entrypoint used elsewhere) to
resolve the correct identity_index before deriving the auth key hash. Ensure the
adjusted path handles errors the same way and preserves the existing network and
key_index (still 0) semantics.

In `@packages/rs-platform-wallet/src/platform_wallet_info/mod.rs`:
- Around line 202-204: Don't coerce missing timestamps to 0: when extracting
created_at_core_block_height and created_at from doc, treat missing values as an
error instead of using unwrap_or(0). Replace the unwrap_or(0) calls on
doc.created_at_core_block_height() and doc.created_at() with checks that
return/propagate an error (e.g., map to Err or use ok_or/ok_or_else) so the
caller can log and skip the malformed document; reference the symbols
created_at_core_block_height, created_at and doc in mod.rs to locate and update
the extraction logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ef11c6c2-cdd5-4200-ab66-60d6f1d31c60

📥 Commits

Reviewing files that changed from the base of the PR and between c3e0a83 and 5bfe3d2.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • packages/rs-platform-wallet/Cargo.toml
  • packages/rs-platform-wallet/src/platform_wallet_info/identity_discovery.rs
  • packages/rs-platform-wallet/src/platform_wallet_info/key_derivation.rs
  • packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs
  • packages/rs-platform-wallet/src/platform_wallet_info/mod.rs
  • packages/rs-platform-wallet/src/platform_wallet_info/wallet_transaction_checker.rs

Comment on lines +82 to +89
Err(e) => {
tracing::warn!(
identity_index,
"Failed to query identity by public key hash: {}",
e
);
consecutive_misses += 1;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't spend the gap budget on query failures.

A Platform/SDK error is not a confirmed empty slot. Incrementing consecutive_misses here can stop the scan early and skip identities later in the range. Either bubble the error up, or log/retry without counting it as a miss.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-platform-wallet/src/platform_wallet_info/identity_discovery.rs`
around lines 82 - 89, The Err(e) arm currently increments consecutive_misses
(variable consecutive_misses) which treats query failures as empty slots;
instead do not count errors as misses—either propagate the error out from the
current function (replace the Err(e) branch with an early return/return Err(e)
or use the ? operator) or log and retry without modifying consecutive_misses;
keep the tracing::warn call but remove the consecutive_misses += 1 so query
failures don't stop the scan prematurely.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 33b3da2 — removed the consecutive_misses += 1 from the error branch. Query failures now just log a warning without consuming gap budget.

Comment on lines +82 to +83
// Derive the first authentication key hash (identity_index 0, key_index 0)
let key_hash_array = derive_identity_auth_key_hash(wallet, self.network(), 0, 0)?;
Copy link
Contributor

@coderabbitai coderabbitai bot Mar 6, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This still only checks the first identity slot.

Every asset-lock follow-up derives identity_index = 0, so a wallet that registers a second identity will keep re-querying the first auth key and never discover the newer one. Since wallet_transaction_checker.rs triggers this path automatically, those identities stay invisible unless a separate discovery scan runs. Please hand this path off to the new gap-limit discovery flow, or derive the candidate index from wallet state instead of hardcoding slot 0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs`
around lines 82 - 83, The code in matured_transactions.rs currently hardcodes
identity_index = 0 when calling derive_identity_auth_key_hash(wallet,
self.network(), 0, 0), which prevents discovery of identities beyond the first
slot; change this to use the wallet's known identity candidate index or invoke
the gap-limit discovery flow instead of a fixed 0. Locate
derive_identity_auth_key_hash usage in matured_transactions.rs and replace the
literal 0 for identity_index with a value obtained from the wallet state (e.g.,
the candidate identity index accessor on the Wallet object) or call the new
discovery function (the gap-limit discovery entrypoint used elsewhere) to
resolve the correct identity_index before deriving the auth key hash. Ensure the
adjusted path handles errors the same way and preserves the existing network and
key_index (still 0) semantics.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is intentional for now. The asset lock path (fetch_contact_requests_for_identities_after_asset_locks) is a quick check triggered when a new asset lock transaction is detected — it checks whether the primary identity (index 0) has been registered. The full gap-limit discovery scan in discover_identities() handles discovering additional identities across all indices.

Wiring the asset lock path into the gap-limit scan would add complexity that isn't needed yet (multi-identity wallets aren't common in practice). If/when that becomes a requirement, we can refactor this path to call discover_identities instead. For now, the separation keeps the two flows simple and distinct.

Copy link
Contributor

Choose a reason for hiding this comment

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

@thepastaclaw, that makes sense — keeping the asset lock path as a lightweight primary-identity check and leaving full gap-limit discovery to discover_identities() is a clean separation of concerns. I'll note this design intent for future reviews.

(ミ ᵕ ꒳ ᵕ ミ)✨


✏️ Learnings added
Learnt from: thepastaclaw
Repo: dashpay/platform PR: 3206
File: packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs:82-83
Timestamp: 2026-03-06T13:10:32.252Z
Learning: In `packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs`, the hardcoded `identity_index = 0` in `fetch_contact_requests_for_identities_after_asset_locks` (via `derive_identity_auth_key_hash(wallet, self.network(), 0, 0)`) is intentional. This path is a quick check triggered when a new asset lock transaction is detected, targeting only the primary identity (index 0). Full gap-limit discovery across all identity indices is handled separately by `discover_identities()`. The separation is deliberate to keep both flows simple; multi-identity wallet support on the asset lock path can be added later by calling `discover_identities` if needed.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

- Only push to discovered list when identity is actually new (avoids
  reprocessing existing identities in discover_identities_with_contacts)
- Use identity() instead of identities().contains_key() to avoid
  cloning the entire identities map
- Don't increment consecutive_misses on query failures (a network/SDK
  error is not a confirmed empty slot and shouldn't consume gap budget)
- Treat missing created_at and created_at_core_block_height as errors
  instead of silently coercing to 0, consistent with other required
  contact request fields
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