fix(rs-sdk): case-insensitive .dash suffix in DPNS name resolution#3914
Conversation
Extracted from PR #3585 (fix 1 of 2). resolve_dpns_name now compares the .dash suffix case-insensitively via eq_ignore_ascii_case, and both resolve_dpns_name and is_dpns_name_available skip the DPNS contract fetch for empty/normalized-empty labels (treating them as not-found rather than erroring or making a needless network call). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughTwo private helper functions ( ChangesDPNS Label Normalization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
✅ Review complete (commit 371877a) |
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Small, well-scoped client-SDK fix that adds case-insensitive .dash suffix handling and aligns the empty-label short-circuit between is_dpns_name_available and resolve_dpns_name. No consensus or FFI surface area is touched. Two non-blocking suggestions remain around test coverage of the new short-circuit and of the updated fetch_many non-existence semantics.
🟡 2 suggestion(s)
1 additional finding(s) omitted (not in diff).
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/rs-sdk/src/platform/dpns_usernames/mod.rs`:
- [SUGGESTION] packages/rs-sdk/src/platform/dpns_usernames/mod.rs:397-411: Add a test that locks in the empty-label short-circuit before the contract fetch
The new guard makes `""` / `".dash"` / `".DASH"` return `Ok(false)` (and `Ok(None)` in `resolve_dpns_name`) without invoking `fetch_dpns_contract` or the network. This is the second observable contract change in this PR and is one of the motivations called out in the PR description. The existing tests only assert that `normalize_dpns_label("")` equals `""`; they don't pin down that the early return happens before `fetch_dpns_contract` requires a context provider. A small test (e.g. invoking `is_dpns_name_available` / `resolve_dpns_name` on a `Sdk` with no context provider and asserting `Ok(false)` / `Ok(None)`) would catch a future reordering that re-introduces the wasted round-trip.
- [SUGGESTION] packages/rs-sdk/src/platform/dpns_usernames/mod.rs:439-446: Pin down `fetch_many` non-existence semantics with a test
The check changed from `is_empty()` to `documents.values().all(|d| d.is_none())`, and the new comment asserts that a proven non-existence comes back as a non-empty `BTreeMap` whose values are all `None`. `all()` on an empty iterator returns `true`, so if `fetch_many` can ever surface an empty map (e.g. via a transport path that doesn't error out), `is_dpns_name_available` would now report "available" — the opposite of the prior `is_empty()` behavior. The change is plausibly correct and matches the SDK's general proof-handling style, but there is no test in this PR that pins the contract down. A unit/mock test covering (a) empty map, (b) map with one `None`, (c) map with one `Some(doc)` would prevent silent regressions.
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Cumulative re-review at fe79734. The latest push (since 11666c6) is only a v3.1-dev merge with no DPNS-relevant delta; the case-insensitive .dash stripping, shared normalize_dpns_label, empty-label short-circuit, and fetch_many semantics change carry over unchanged. No new latest-delta findings. Both prior findings are carried forward as STILL VALID — added unit tests cover only pure helpers (normalize_dpns_label, extract_dpns_label), not the public async behavior contracts that this PR newly establishes.
🟡 2 suggestion(s)
1 additional finding(s) omitted (not in diff).
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/rs-sdk/src/platform/dpns_usernames/mod.rs`:
- [SUGGESTION] packages/rs-sdk/src/platform/dpns_usernames/mod.rs:397-411: Carried forward (STILL VALID): no test pins the empty-label short-circuit before contract fetch
Verified against current head. The empty-label guard at lines 409-411 in `is_dpns_name_available` (and the mirror at lines 467-469 in `resolve_dpns_name`) is one of the two observable behavior changes this PR introduces — `""`, `".dash"`, and `".DASH"` now return `Ok(false)` / `Ok(None)` without invoking `fetch_dpns_contract` or any network round-trip. The newly added tests at lines 530-562 only exercise the pure `normalize_dpns_label` / `extract_dpns_label` helpers and never call the two public async methods, so a regression that moves the guard below `fetch_dpns_contract().await?` would silently re-introduce the wasted round-trip and slip through CI. Add a mock-SDK test that calls `is_dpns_name_available` / `resolve_dpns_name` with empty / suffix-only inputs and asserts the call resolves to `Ok(false)` / `Ok(None)` without the contract fetch path being reached.
- [SUGGESTION] packages/rs-sdk/src/platform/dpns_usernames/mod.rs:439-446: Carried forward (STILL VALID): fetch_many non-existence semantics still untested
Verified against current head. The availability predicate was flipped from `documents.is_empty()` to `documents.values().all(|d| d.is_none())`, and the accompanying comment asserts that a proven non-existence comes back as a non-empty `BTreeMap` whose values are all `None`. The risk is asymmetric: if `fetch_many` ever returns an empty map (transport/proof edge case, mock SDK path, or future refactor), `all()` on an empty iterator returns `true` and the name is reported available — the inverse of the pre-PR behavior, and a security-relevant misclassification because callers may gate registration attempts on this. Conversely a `{id -> None}` response now correctly reports available where the old `is_empty()` check would have reported taken (this is the bug being fixed). Add focused unit/mock coverage for the three observable cases: (a) empty map → expected `false` (treat as proof not seen), (b) map containing only `None` → expected `true`, (c) map containing `Some(document)` → expected `false`. This locks the `fetch_many` contract in place so it can't silently regress.
Empty commit to start a fresh Tests run that reads the updated UBUNTU_BACKUP_ENABLED repo variable (in-flight runs captured the old value). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Verified at 371877a — implementation correctly fixes case-insensitive .dash suffix handling and short-circuits empty normalized labels. Latest delta is a CI-retrigger with no file changes, so two prior test-coverage suggestions are carried forward unchanged: the empty-label short-circuit and the fetch_many non-existence semantics still lack public-API tests pinning the new contracts.
🟡 1 suggestion(s)
1 additional finding(s) omitted (not in diff).
1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/rs-sdk/src/platform/dpns_usernames/mod.rs`:
- [SUGGESTION] packages/rs-sdk/src/platform/dpns_usernames/mod.rs:439-446: Carried forward: `values().all(|d| d.is_none())` non-existence semantics are not pinned by a test
Verified at HEAD 371877ae. The availability check moved from `documents.is_empty()` to `documents.values().all(|d| d.is_none())` and now depends on a non-obvious contract: `Document::fetch_many` returns a `BTreeMap<Identifier, Option<Document>>` where proven non-existence comes back as a non-empty map with `None` values. The inline comment at lines 441–445 captures this correctly, but no test exercises either shape (empty map vs. all-`None` map) against `is_dpns_name_available`. If the SDK/Drive proof-verifier layer ever changes the shape — e.g. returns an empty map for non-existence proofs — the predicate flips silently from "available" to "taken" with no regression signal. A mock-based test using the existing SDK mock-mode harness would lock in the contract this caller now relies on.
|
One test failing due to v3.1-dev issue, not related to our changes, fixed in #3900 . |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## v3.1-dev #3914 +/- ##
============================================
+ Coverage 71.20% 72.19% +0.99%
============================================
Files 20 21 +1
Lines 2837 2946 +109
============================================
+ Hits 2020 2127 +107
- Misses 817 819 +2
🚀 New features to boost your workflow:
|
Issue being fixed or feature implemented
.dashsuffix case-sensitively.resolve_dpns_namestripped the suffix only when it was exactly".dash", so a name like"Alice.DASH"or"alice.Dash"was treated as a bare label including the suffix and normalized whole — producing the wrongnormalizedLabeland failing to resolve a name that does exist."alice.DASH"(or any mixed-case suffix) → the SDK queriesnormalizedLabel == "a11ce.dash"instead of"a11ce"→ resolution returns "not found" for a registered name. Separately, empty/suffix-only input ("",".dash") triggers a needless DPNS contract fetch + network round-trip before failing.What was done?
Scoped entirely to
packages/rs-sdk/src/platform/dpns_usernames/mod.rs:extract_dpns_label— strips a trailing.dashsuffix matched case-insensitively viaeq_ignore_ascii_case, leaving non-.dashinputs untouched.normalize_dpns_label— combines suffix extraction withconvert_to_homograph_safe_chars, giving a single value suitable for matching thenormalizedLabelfield ofdomaindocuments.resolve_dpns_nameandis_dpns_name_availableboth route input throughnormalize_dpns_label, and both short-circuit on an empty normalized label before fetching the DPNS contract — no wasted network call for""/".dash". The two APIs agree on malformed input.test_extract_dpns_labelandtest_normalize_dpns_label_strips_dash_suffix_case_insensitivelycover mixed-case suffixes, non-.dashsuffixes, and empty/suffix-only inputs.How Has This Been Tested?
cargo build -p dash-sdk— clean.cargo test -p dash-sdk --lib -- platform::dpns_usernames::tests— 5 passed, 0 failed (2 new + 3 pre-existing, no regressions).cargo fmt -p dash-sdk -- --check— clean.cargo clippy -p dash-sdk— no new warnings.Breaking Changes
None. The public parameter of
is_dpns_name_availableis namedname(it accepts both a bare label and a fullname.dashform). Rust has no named arguments, so this is not an API/ABI break.Checklist:
For repository code-owners and collaborators only
🤖 Co-authored by Claudius the Magnificent AI Agent
Summary by CodeRabbit
Release Notes
Bug Fixes
Tests