refactor(sdk): per-network protocol-version floor + version_pinned unification#3900
refactor(sdk): per-network protocol-version floor + version_pinned unification#3900Claudius-Maginificent wants to merge 11 commits into
Conversation
…e initial protocol version floor Replace the per-network min_protocol_version (mainnet 11, testnet/devnet/regtest 12) and its build()/post-refresh clamps with a single cross-network initial protocol version floor of 11 (DEFAULT_INITIAL_PROTOCOL_VERSION = PROTOCOL_VERSION_11). The initial version is now the ratchet floor; refresh_protocol_version() still ratchets up as the network's proven version is observed. Deliberate trade-off: non-mainnet networks (live on PV 12) now seed at 11 and rely on the proven-query refresh to climb to 12; until a refresh succeeds they sit one version low. Also resolves the v3.1-dev CI failure in dash-sdk's sdk_builder_default_seeds_atomic_to_floor caused by the #3809/#3886/#3893 protocol-version interaction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR refactors protocol-version floor logic by converting ChangesProtocol-Version Floor Rework
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 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 |
…inline refresh, drop redundant runtime clamp Addresses both PR #3900 review comments. Part A: restore the per-network `const fn min_protocol_version` (mainnet → 11; testnet/devnet/regtest → 12) as the single source of the build() floor, replacing `DEFAULT_INITIAL_PROTOCOL_VERSION`. build() now floors via `version.protocol_version.max(min_protocol_version(self.network))`. The `DEFAULT_INITIAL_PROTOCOL_VERSION` const is removed; no `MIN_PROTOCOL_VERSION` const is introduced. All references (code, tests, docs) repoint to `min_protocol_version(...)` or the right per-network value. Part B: inline `refresh_protocol_version` into an `impl Sdk` block in sdk.rs (~10 lines) and delete `packages/rs-sdk/src/sdk/refresh.rs` plus its `mod refresh;` declaration. `ExtendedEpochInfo::fetch_current` already ratchets the version internally via the proven-metadata path, so the post-refresh runtime clamp is removed as redundant: build() floors per-network and the ratchet is monotonic-up; a network switch is a fresh build(), not a runtime mutation. Tests reverted to per-network reality: testnet/devnet/regtest default builder boots at 12 directly; mainnet seeds at 11. The relocated refresh tests exercise the real `refresh_protocol_version` end to end — testnet (live at 12 == latest) confirms its floor through the proven query; the generic ratchet test still proves an upward 10→12 climb. No under-shoot trade-off — per-network floors are restored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
✅ Review complete (commit 23832dc) |
There was a problem hiding this comment.
Pull request overview
This PR aims to restore correct SDK protocol-version boot behavior by reintroducing a per-network minimum protocol-version floor (instead of a single cross-network default), and by simplifying protocol-version refresh to use the existing proven-query ratchet path.
Changes:
- Replaces the single initial protocol-version constant with a
min_protocol_version(network)floor used duringSdkBuilder::build(). - Inlines
Sdk::refresh_protocol_versionintosdk.rsand deletes the dedicatedsdk/refresh.rsmodule. - Updates fetch/encoder tests and shared test helpers to assert the new “boot at per-network floor” behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/rs-sdk/src/sdk.rs | Implements protocol-version floor + refresh changes; updates builder seeding and related tests. |
| packages/rs-sdk/src/sdk/refresh.rs | Removes the old refresh module (refresh logic moved into sdk.rs). |
| packages/rs-sdk/tests/fetch/document_query_v0_v1.rs | Updates tests to assert default builder seeds to the mainnet floor instead of the removed constant. |
| packages/rs-sdk/tests/fetch/common.rs | Updates documentation/comments in shared test helpers to describe per-network floor boot behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@packages/rs-sdk/src/sdk.rs`:
- Around line 62-64: The min_protocol_version function ignores its network
parameter (indicated by the underscore prefix) and always returns
PROTOCOL_VERSION_10, but the tests expect per-network values: Mainnet should
return PROTOCOL_VERSION_11 and Testnet/Devnet/Regtest should return
PROTOCOL_VERSION_12. Remove the underscore prefix from the network parameter and
implement a match statement to return the appropriate protocol version based on
the network variant, returning PROTOCOL_VERSION_11 for Mainnet and
PROTOCOL_VERSION_12 for the other network types.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 093f5a31-599c-4e7b-b043-4896611f61e9
📒 Files selected for processing (4)
packages/rs-sdk/src/sdk.rspackages/rs-sdk/src/sdk/refresh.rspackages/rs-sdk/tests/fetch/common.rspackages/rs-sdk/tests/fetch/document_query_v0_v1.rs
💤 Files with no reviewable changes (1)
- packages/rs-sdk/src/sdk/refresh.rs
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
All six agents independently flagged the same blocking issue: min_protocol_version at packages/rs-sdk/src/sdk.rs:62-64 ignores its Network argument and returns PROTOCOL_VERSION_10 for every network. Verified against the source — this directly contradicts the new in-file tests (test_min_protocol_version_mapping, test_testnet_default_builder_boots_at_per_network_floor, test_testnet_refresh_confirms_floor_via_proven_query) and reintroduces (and widens) the fee-under-reservation window the PR description claims to close. The accompanying doc comments still describe a per-network floor that no longer exists.
🔴 1 blocking
🤖 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/sdk.rs`:
- [BLOCKING] packages/rs-sdk/src/sdk.rs:62-64: min_protocol_version returns v10 for every network — defeats the PR's purpose and breaks the new tests
`min_protocol_version` discards its `Network` argument and unconditionally returns `dpp::version::v10::PROTOCOL_VERSION_10`, with a `TODO` to set real per-network floors later. This is the helper `SdkBuilder::build()` uses to seed `initial_protocol_version`, so every unpinned SDK now boots at v10 — mainnet boots below its v11 live floor, and testnet/devnet/regtest boot two versions below their v12 live floor.
Concrete consequences in this PR:
1. The three new tests added in the same module fail at runtime:
- `test_min_protocol_version_mapping` (sdk.rs:1922) asserts Mainnet → `PROTOCOL_VERSION_11` and Testnet/Devnet/Regtest → `PROTOCOL_VERSION_12`.
- `test_testnet_default_builder_boots_at_per_network_floor` (sdk.rs:1944) asserts the testnet SDK boots at `PROTOCOL_VERSION_12`.
- `test_testnet_refresh_confirms_floor_via_proven_query` (sdk.rs:1967) asserts `dpp::version::LATEST_VERSION == floor`, which is false when `floor == 10`.
2. The PR description's stated regression fix is undone. The PR explains that an unpinned SDK on testnet/devnet/regtest was 'booting one protocol version low (at 11 instead of those networks' live 12)' and that fee-sensitive flows (shielded shield/unshield/transfer/withdraw) size their reserve off `Sdk::version()`. With the floor pinned at v10 for every network — and the previous runtime `fetch_max` clamp in `refresh_protocol_version` removed in this PR — the under-shoot window is strictly wider than before this PR.
3. The surrounding doc comments (sdk.rs:56–61 and elsewhere) still describe a per-network hard lower bound and claim 'testnet boots directly at 12', which no longer matches the implementation.
Either restore the per-network mapping the rest of the PR (description, tests, doc comments) was built around, or — if a single uniform floor is intentional — revise the PR title, description, tests, and re-evaluate the fee-under-reservation risk for non-mainnet networks before landing.
The pin concept was named two inconsistent, opposite-polarity ways: `SdkBuilder.version_explicit` (true = pinned) and `Sdk.auto_detect_protocol_version` (true = auto-detect, i.e. NOT pinned), wired together as `auto_detect_protocol_version: !self.version_explicit`. Collapse both onto a single name and polarity: `version_pinned` (true = version is pinned, auto-detection disabled). The builder field is a straight rename; the Sdk field inverts, so every read/assert flips: - `maybe_update_protocol_version`: `if !auto_detect` -> `if version_pinned` - `refresh_protocol_version`: `if auto_detect` -> `if !version_pinned` - `build()` wiring drops the negation: `version_pinned: self.version_pinned` No behavioural change. fmt + clippy (-D warnings, --all-features) clean; 147 dash-sdk lib tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub>
|
✅ DashSDKFFI.xcframework built for this PR.
SwiftPM (host the zip at a stable URL, then use): .binaryTarget(
name: "DashSDKFFI",
url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
checksum: "152b8b74e130dd3c7cee1e0d04f5e32707d038f622a1a73213616b4d08db220e"
)Xcode manual integration:
|
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Carried-forward prior finding from 8b03937 is STILL VALID at head 42f75e0: min_protocol_version at packages/rs-sdk/src/sdk.rs:62-64 still ignores its Network argument and returns PROTOCOL_VERSION_10 for every network, directly contradicting the PR's own tests (test_min_protocol_version_mapping asserts v11/v12) and the PR's stated goal of booting mainnet at 11 and testnet/devnet/regtest at 12. The latest-push delta (rename of auto_detect_protocol_version to version_pinned and boolean polarity inversion) is mechanically clean and introduces no new latest-delta findings. Carried-forward: 1 blocking. New: 0.
1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.
…ersion-floor' into refactor/sdk-collapse-protocol-version-floor
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Carried-forward prior finding from 42f75e0 is STILL VALID at 21ea0d9: min_protocol_version at sdk.rs:64-66 still returns PROTOCOL_VERSION_10 unconditionally with a TODO, while the PR description and title explicitly promise per-network floors (Mainnet→v11, Testnet/Devnet/Regtest→v12). The PR's central stated goal therefore is not implemented; unpinned testnet/devnet/regtest SDKs boot two versions below the live network protocol until the first proven metadata refresh, re-opening the fee-under-reservation window the PR was written to close. A secondary issue from the latest delta: build() no longer clamps caller-supplied with_initial_version against min_protocol_version, so once the per-network mapping is corrected, a sub-floor initial seed would still slip through (with_version pins remain intentionally exempt).
🔴 1 blocking | 🟡 1 suggestion(s)
🤖 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/sdk.rs`:
- [BLOCKING] packages/rs-sdk/src/sdk.rs:64-66: min_protocol_version still returns v10 for every network — PR's stated goal is not implemented
Carried-forward prior finding, STILL VALID at this head. `min_protocol_version` ignores its `_network` argument and unconditionally returns `dpp::version::v10::PROTOCOL_VERSION_10` with a TODO deferring the real per-network mapping. The PR description explicitly commits Mainnet→`PROTOCOL_VERSION_11` and Testnet/Devnet/Regtest→`PROTOCOL_VERSION_12`, and frames the whole change as closing a fee-under-reservation window for shielded flows that size reserves from `Sdk::version()` before the first proven response.
Consequences observable at this SHA:
- `SdkBuilder::build()` (sdk.rs:1081-1084) seeds every unpinned network at v10. Testnet/devnet/regtest under-shoot the live floor by two versions instead of one, which is strictly worse than the cross-network constant the PR claims to have replaced.
- `test_testnet_default_builder_boots_at_per_network_floor` (sdk.rs:1885-1897) asserts `sdk.protocol_version_number() == min_protocol_version(Network::Testnet)`. Because both sides resolve through the same function, the assertion is tautological and passes against any uniform floor; it does NOT verify the PR's stated invariant.
- The PR description claims a `test_min_protocol_version_mapping` test guards the mapping, but no such test exists in this checkout.
Until the per-network mapping is implemented and guarded by a literal-value test (e.g. `assert_eq!(min_protocol_version(Network::Testnet), PROTOCOL_VERSION_12)`), the surrounding refactor (refresh inlining, clamp removal, field rename) is cosmetic and the original regression remains.
- [SUGGESTION] packages/rs-sdk/src/sdk.rs:1081-1084: build() does not floor an explicit with_initial_version against the per-network minimum
The PR description states: "`build()` floors per-network. `initial_protocol_version = self.version.protocol_version.max(min_protocol_version(self.network))`." The actual code uses `self.version.unwrap_or_else(...)`, so a caller invoking `with_initial_version(pv)` where `pv.protocol_version < min_protocol_version(self.network)` is NOT lifted to the floor. `with_version` pins remain intentionally exempt (sdk.rs:949-950, guarded by the pin-below-floor test), but `with_initial_version` is documented as a seed, not a pin — its docstring says auto-detect already starts at the per-network floor, so an explicit seed below the floor contradicts the documented contract. Once the blocking finding above is fixed, this gap is what allows a caller to re-open the under-reservation window. Pair the floor mapping fix with a `max()` clamp here.
The PV-floor change on this branch flattened min_protocol_version() to PROTOCOL_VERSION_10 for all networks and removed floor-clamping of pinned versions. Two test suites still encoded the old expectations: - rs-sdk sdk_builder_default_seeds_atomic_to_floor asserted the hardcoded PROTOCOL_VERSION_11 constant; now asserts PROTOCOL_VERSION_10. - wasm-sdk builder chaining tests expected withVersion(1) to be raised to the network floor; pinned versions are now used as-is, so the assertions move from greaterThan(1) to equal(1). <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Carried-forward verification: prior finding #1 (flat v10 floor) and #2 (with_initial_version not floored) are both classified per the current PR contract — #1 is INTENTIONALLY DEFERRED (TODO at sdk.rs:65 explicitly tracks restoration; docs frame v10 as a seed for auto-detect) and #2 is OUTDATED (with the lowest known PV as the floor and with_initial_version documented as a deliberate auto-detect seed, no clamp is required). One new cumulative finding remains: the PR description promises eager refresh_protocol_version on every real init path (native, FFI dash_sdk_create*, WASM constructor), but the code at f7d9154 does not wire it into any of those paths — only the explicit caller-driven dash_sdk_refresh_protocol_version FFI symbol and Swift wrapper invoke it. Because this PR simultaneously lowers the mainnet floor from v11 to v10, the gap the PR claims to close is in fact widened for shielded fee-sensitive flows that compute reserves from Sdk::version() before the first proven response ratchets the atomic upward. The latest-push delta itself is test-only and reconciles assertions to the new flat floor and the no-clamp behavior; those test changes are correct.
🔴 1 blocking
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/sdk.rs`:
- [BLOCKING] packages/rs-sdk/src/sdk.rs:1075-1199: Real SDK init paths return before the proven refresh runs, contradicting the PR's stated safety story
The PR description justifies collapsing `min_protocol_version` to a flat `PROTOCOL_VERSION_10` (which is below mainnet's live `PROTOCOL_VERSION_12`) by stating that `refresh_protocol_version()` is invoked eagerly on every real init path — native, the FFI `dash_sdk_create*` entry points (via the FFI runtime), and the WASM constructor — so the version is correct before the first real query. That wiring is not present at this head:
- `SdkBuilder::build()` (sdk.rs:1075-1199) is synchronous; it seeds the atomic with `min_protocol_version` (v10) and returns without invoking refresh.
- `dash_sdk_create`, `dash_sdk_create_extended`, `dash_sdk_create_trusted`, and `dash_sdk_create_with_callbacks` in `packages/rs-sdk-ffi/src/sdk.rs` all return immediately after `builder.build()` without `runtime.block_on(wrapper.sdk.refresh_protocol_version())`. Only the standalone, caller-driven `dash_sdk_refresh_protocol_version` symbol calls it.
- `WasmSdkBuilder::build()` (packages/wasm-sdk/src/sdk.rs:315) just calls `self.inner.build()` and returns the wrapper.
Auto-detect via `verify_response_metadata` → `maybe_update_protocol_version` still ratchets the version after the first proven response, but it cannot help any code path that reads `Sdk::version()` before that first response — which is exactly the pre-query window the PR cites for shielded shield/unshield/transfer/withdraw fee reserves. Before this PR, mainnet seeded at v11, so the gap to a v12 network was one version; with v10 as the new floor and no eager refresh wired, the gap is two versions on first use.
Either wire `refresh_protocol_version` into the real init paths as the description promises (e.g. an async `build_and_refresh` on `SdkBuilder` plus `runtime.block_on(refresh)` after `builder.build()` in each `dash_sdk_create*` and an `await` in `WasmSdkBuilder::build`), or restore a higher per-network floor (the prior behavior) and amend the description to make clear that eager refresh on init is the caller's responsibility on the FFI/WASM paths. Shipping a v10 floor with the eager-refresh story un-wired is the worst combination for the fee-reserve regression the PR is meant to address.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## v3.1-dev #3900 +/- ##
============================================
+ 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:
|
…e sdk.rs comments The initial-version-11 bump (0771206) updated the unit test but left document_query_v0_v1::sdk_builder_default_seeds_atomic_to_floor asserting PROTOCOL_VERSION_10 against an 11 floor. Assert the real floor instead and clear comments left stale by the floor/rename/refresh-relocation refactor. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Latest push (0771206 'chore: initial version 11') bumps min_protocol_version from PV10 to PV11 in sdk.rs:65, but the integration test sdk_builder_default_seeds_atomic_to_floor in tests/fetch/document_query_v0_v1.rs:229 still asserts PROTOCOL_VERSION_10 — CI will fail deterministically. The PR description also still describes the floor as PV10, so code, test, and description are three-way out of sync. Prior finding about real init paths not running refresh_protocol_version is INTENTIONALLY DEFERRED per the updated PR body, which scopes refresh-on-init wiring to #3902 and keeps native rs-sdk caller-driven.
🔴 1 blocking
🤖 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/tests/fetch/document_query_v0_v1.rs`:
- [BLOCKING] packages/rs-sdk/tests/fetch/document_query_v0_v1.rs:226-230: Floor bumped to PV11 but integration test still asserts PV10 — CI will fail
Commit 077120681 raised `min_protocol_version()` in `packages/rs-sdk/src/sdk.rs:65` from `PROTOCOL_VERSION_10` to `PROTOCOL_VERSION_11`. `SdkBuilder::new_mock()` defaults to `Network::Mainnet` and `build()` (sdk.rs:1081-1084, 1178) seeds the atomic from `min_protocol_version(self.network)`, so `sdk_default.version().protocol_version` is now 11. But this test still hard-codes the assertion to `dpp::version::v10::PROTOCOL_VERSION_10`, so the assertion will fail every run under `cargo test -p dash-sdk --features mocks`.
The in-crate refresh test `test_refresh_ratchets_up_via_proven_query` was updated in this same delta to use `super::min_protocol_version(Network::Mainnet)` (floor-agnostic), but the equivalent external test here was missed. The comment immediately above the assertion (lines 222-225) explicitly says "We assert against the actual floor constant rather than a hardcoded integer so the test survives future floor bumps" — yet the assertion below it does the opposite by binding to the `PROTOCOL_VERSION_10` symbol.
Note that the PR description still describes the floor as `PROTOCOL_VERSION_10` and lists this exact test as already reconciled to `== 10`; that text is stale relative to the head being reviewed. The PR author should either (a) revert the floor bump in sdk.rs:65 back to PV10 and keep the test as-is to match the stated contract, or (b) keep the bump, update the test to PV11, and reconcile the PR description. Because `min_protocol_version` is private to `sdk.rs`, the cleanest in-scope fix if keeping PV11 is to assert against `dpp::version::v11::PROTOCOL_VERSION_11`. A more durable fix (worth a follow-up) would expose the floor via a `pub` accessor so `tests/` files can track future floor bumps automatically.
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Prior PV10/PV11 test-assertion finding is FIXED at head 1976b6b. No new blocking issues in the 0771206..1976b6b delta. Remaining items are documentation staleness — several doc-comments and one test name still describe the protocol-version floor as 'per-network' even though min_protocol_version now returns a flat PV11 baseline — plus a minor API hygiene nit that refresh_protocol_version returns a Result that is always Ok.
💬 2 nitpick(s)
min_protocol_version returns the network-specific minimum (Mainnet -> v11, Testnet/Devnet/Regtest -> v12) instead of a single flat v11 baseline, so an unpinned SDK on a v12 network no longer seeds below the network's live minimum. Kept as a const fn; condensed the rustdoc to the floor-not-a-pin rationale. 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
Cumulative review of the rs-sdk protocol-version floor/pinning/refresh refactor at 02b63c5. The per-network floor is correctly restored (Mainnet→PV11, Testnet/Devnet/Regtest→PV12), version_pinned polarity is consistent, the proven-only refresh path is sound, and tests cover floor seeding, sub-floor pin preservation, upward ratchet, and non-fatal refresh failure. Remaining items are documentation/API-shape nitpicks around the newly public surface and the always-Ok refresh signature.
💬 4 nitpick(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.
| /// Per-network lower bound an unpinned SDK seeds from and never drops below. | ||
| /// | ||
| /// This is a **lower bound, not a pin**: auto-detect | ||
| /// ([`Sdk::maybe_update_protocol_version`]) still ratchets the version *upward* | ||
| /// via `fetch_max` when the network reports a newer one. The floor only stops it | ||
| /// from going below the network's known minimum. | ||
| /// | ||
| /// Single source of truth for the floor lives here in `rs-sdk`; the FFI and | ||
| /// Swift layers call into the SDK and need no floor logic of their own. Bump the | ||
| /// per-network values here as each network's live minimum advances. | ||
| /// | ||
| /// ## Mapping | ||
| /// | ||
| /// - [`Network::Mainnet`] → 11 | ||
| /// - [`Network::Testnet`] → 12 | ||
| /// - [`Network::Devnet`] → 12 | ||
| /// - [`Network::Regtest`] → 12 | ||
| fn min_protocol_version(network: Network) -> u32 { | ||
| /// A floor, not a pin: auto-detect ([`Sdk::maybe_update_protocol_version`]) still | ||
| /// ratchets the version *upward* via `fetch_max` when the network reports a newer | ||
| /// one. |
There was a problem hiding this comment.
💬 Nitpick: min_protocol_version doc overstates the floor as a runtime lower bound
The rustdoc says an unpinned SDK "seeds from and never drops below" this value. After this PR the construction-time clamp is gone and there is no refresh-time clamp: with_initial_version (now public) can seed an unpinned SDK below the floor, and with_version can pin below the floor (see test_explicit_pin_below_floor_is_preserved). The accurate framing is that this is the default seed for unpinned SDKs without with_initial_version, and the stored version is monotonic-upward via fetch_max but not bounded below at runtime. Align the doc with the new no-clamp semantics so readers don't infer a guarantee the code no longer enforces.
source: ['claude']
There was a problem hiding this comment.
Resolved in this update — min_protocol_version doc overstates the floor as a runtime lower bound no longer present.
Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.
| /// Configure initial platform version, replacing default defined in [`min_protocol_version`]. | ||
| /// | ||
| /// Auto-detect already starts every unpinned SDK at | ||
| /// [`DEFAULT_INITIAL_PROTOCOL_VERSION`] and ratchets upward via `fetch_max` in | ||
| /// Auto-detect already starts every unpinned SDK at the per-network | ||
| /// [`min_protocol_version`] and ratchets upward via `fetch_max` in | ||
| /// `maybe_update_protocol_version` once the network's version is observed. This | ||
| /// seed exists only to let unit tests start *below* that floor — exercising the | ||
| /// upward-only ratchet from an older network's version without disabling auto-detect. | ||
| /// function allows overriding the initial seed version that auto-detect starts with. | ||
| /// | ||
| /// Seeds `self.version` and keeps `version_explicit` `false`, so auto-detect stays | ||
| /// Seeds `self.version` and keeps `version_pinned` `false`, so auto-detect stays | ||
| /// on. Builder chains are last-write-wins: a later `with_initial_version` re-enables | ||
| /// auto-detect that an earlier `with_version` disabled. | ||
| #[cfg(test)] | ||
| pub(crate) fn with_initial_version(mut self, version: &'static PlatformVersion) -> Self { | ||
| self.version = version; | ||
| self.version_explicit = false; | ||
| pub fn with_initial_version(mut self, version: &'static PlatformVersion) -> Self { | ||
| self.version = Some(version); | ||
| self.version_pinned = false; | ||
| self | ||
| } |
There was a problem hiding this comment.
💬 Nitpick: Public with_initial_version doc still reads as an internal/test helper
with_initial_version was previously pub(crate) + #[cfg(test)] with a doc framing it as a test-only seed for exercising the upward ratchet. It is now pub, but the rustdoc still reads as an internal helper and does not warn callers about the sub-floor seed hazard. Because the construction-time floor clamp was deliberately removed, a public caller passing a version below min_protocol_version will operate below the network's live version until a proven response arrives. Restate the intended use (testing / older-network catch-up), call out the caller-owned hazard, and point production callers at refresh_protocol_version() for eager correction.
source: ['claude']
There was a problem hiding this comment.
Resolved in this update — Public with_initial_version doc still reads as an internal/test helper no longer present.
Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.
| /// Return [Dash Platform version](PlatformVersion) information used by this SDK. | ||
| /// | ||
| /// The version is floored at construction to at least the per-network minimum | ||
| /// protocol version (`min_protocol_version`), so it is never below the network's | ||
| /// known live version. With auto-detection (default) the SDK starts at | ||
| /// `max(DEFAULT_INITIAL_PROTOCOL_VERSION, network floor)` and then tracks the | ||
| /// network's version — auto-detection only ever ratchets *upward* (`fetch_max`). | ||
| /// A version pinned via [`SdkBuilder::with_version()`] is returned as pinned, | ||
| /// except that a pin below the network floor is raised to the floor at build time. | ||
| /// With auto-detection (default) the SDK starts at the per-network | ||
| /// [`min_protocol_version`] and then tracks the network's version — | ||
| /// auto-detection only ever ratchets *upward* (`fetch_max`). A version pinned | ||
| /// via [`SdkBuilder::with_version()`] is returned as pinned. |
There was a problem hiding this comment.
💬 Nitpick: Sdk::version() doc omits with_initial_version as a seed override
The doc on version() says "With auto-detection (default) the SDK starts at the per-network min_protocol_version". Now that with_initial_version is public, an unpinned SDK's starting point can be a caller-supplied value rather than the floor. A one-line mention of with_initial_version here keeps version()'s contract self-consistent with the newly public surface introduced in this PR.
source: ['claude']
There was a problem hiding this comment.
Resolved in this update — Sdk::version() doc omits with_initial_version as a seed override no longer present.
Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/rs-sdk/src/sdk.rs (1)
374-376:⚠️ Potential issue | 🔴 CriticalCall
fetch_current_with_metadata_and_proof()explicitly to honor refresh's proven-only contract.The documentation states refresh_protocol_version issues a "proven" query, but the implementation calls
ExtendedEpochInfo::fetch_current(), which routes through the genericfetch_with_metadata()→fetch_with_metadata_and_proof()path that honorssdk.query_settings(). This means refresh can consume unproven metadata when the SDK is configured withwith_proofs(false). Either callfetch_current_with_metadata_and_proof()directly to enforce proven-only semantics, or update the documentation to reflect that refresh follows the SDK's proof setting.🤖 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 `@packages/rs-sdk/src/sdk.rs` around lines 374 - 376, In the refresh_protocol_version method, replace the call to ExtendedEpochInfo::fetch_current() with ExtendedEpochInfo::fetch_current_with_metadata_and_proof() to explicitly enforce the proven-only contract that the documentation claims for refresh operations, ensuring that refresh always uses proven metadata regardless of the SDK's general query_settings configuration.
🧹 Nitpick comments (1)
packages/rs-sdk/src/sdk.rs (1)
1088-1188: ⚡ Quick winRun rustfmt on the builder construction block.
This changed block has several non-rustfmt forms (
let sdk=,Sdk{,inner:SdkInstance, extra spaces in calls). Please format before merge.As per coding guidelines, Rust files should be formatted with
cargo fmt --all, follow rustfmt defaults, and use 4-space indentation.🤖 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 `@packages/rs-sdk/src/sdk.rs` around lines 1088 - 1188, Run cargo fmt on the SDK builder construction block in packages/rs-sdk/src/sdk.rs to fix formatting inconsistencies. The block contains several non-rustfmt formatting issues in the Sdk struct initialization (lines 1088-1188), including missing spaces around operators in variable assignments (let sdk=), improper spacing in struct field initialization (Sdk{, inner:SdkInstance), and inconsistent spacing in method calls. Execute cargo fmt --all to automatically reformat this section to comply with rustfmt defaults and 4-space indentation standards.Source: Coding guidelines
🤖 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.
Outside diff comments:
In `@packages/rs-sdk/src/sdk.rs`:
- Around line 374-376: In the refresh_protocol_version method, replace the call
to ExtendedEpochInfo::fetch_current() with
ExtendedEpochInfo::fetch_current_with_metadata_and_proof() to explicitly enforce
the proven-only contract that the documentation claims for refresh operations,
ensuring that refresh always uses proven metadata regardless of the SDK's
general query_settings configuration.
---
Nitpick comments:
In `@packages/rs-sdk/src/sdk.rs`:
- Around line 1088-1188: Run cargo fmt on the SDK builder construction block in
packages/rs-sdk/src/sdk.rs to fix formatting inconsistencies. The block contains
several non-rustfmt formatting issues in the Sdk struct initialization (lines
1088-1188), including missing spaces around operators in variable assignments
(let sdk=), improper spacing in struct field initialization (Sdk{,
inner:SdkInstance), and inconsistent spacing in method calls. Execute cargo fmt
--all to automatically reformat this section to comply with rustfmt defaults and
4-space indentation standards.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9cf04fbc-1d25-4ef4-bb0b-61768eb95e08
📒 Files selected for processing (2)
packages/rs-sdk/src/sdk.rspackages/rs-sdk/tests/fetch/document_query_v0_v1.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/rs-sdk/tests/fetch/document_query_v0_v1.rs
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Cumulative reconciliation against the prior reviewed commit 02b63c5. The PR's behavioral core — version_pinned unification, per-network seed via min_protocol_version, no construction-time clamp, and the inlined refresh_protocol_version ratchet — is sound and well-tested. All five prior nitpicks remain unaddressed in the new HEAD (23832dc); they are carried forward verbatim per verifier policy. One additional nit (truncated test rustdoc) is added. No blocking issues; review action is COMMENT.
💬 2 nitpick(s)
1 additional finding(s) omitted (not in diff).
4 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.
| /// A pin *below* the per-network [`min_protocol_version`] is preserved | ||
| #[test] | ||
| fn test_explicit_pin_overrides_default_floor() { | ||
| fn test_explicit_pin_below_floor_is_preserved() { |
There was a problem hiding this comment.
💬 Nitpick: Truncated rustdoc on test_explicit_pin_below_floor_is_preserved
The single-line /// above the test reads "A pin below the per-network [min_protocol_version] is preserved" with no terminating period and no explanation of the why-it-matters context that the replaced test's block doc carried. Either finish the sentence or expand it to note that the old behavior clamped this up to the floor and the new behavior intentionally preserves the sub-floor pin, mirroring the no-clamp semantics added by this PR.
| /// A pin *below* the per-network [`min_protocol_version`] is preserved | |
| #[test] | |
| fn test_explicit_pin_overrides_default_floor() { | |
| fn test_explicit_pin_below_floor_is_preserved() { | |
| /// A pin *below* the per-network [`min_protocol_version`] is preserved as-is | |
| /// (no construction-time clamp) and `version_pinned` stays `true`. |
source: ['claude']
Why this PR exists
SdkBuilder::version_explicittrue = pinned,Sdk::auto_detect_protocol_versiontrue = not pinned), andrefresh_protocol_versionlived in its own module behind a redundant post-build clamp that silently rewrote a caller's pinned version.with_version()did not actually honour the version you pinned — it bumped a sub-floor pin up to the floor behind your back. Cleaning this up is the groundwork for refreshing the protocol version on SDK init.version_pinnedflag introduced here. The two are intended to land together. (Nativers-sdkinit is wired by neither PR —build()stays synchronous; native callers can callrefresh_protocol_version()themselves or rely on the lazy first-query ratchet. Tracked as follow-up.)What was done
min_protocol_versionis per-network (restored in02b63c5f0a). It is aconst fnreturning the network-specific minimum — Mainnet → v11; Testnet / Devnet / Regtest → v12 — and is the per-network lower bound an unpinned SDK seeds from inbuild(). An earlier iteration of this PR had collapsed it to a single flat v11 baseline; that has been reverted so an unpinned SDK on a v12 network no longer seeds below the network's live minimum. The rustdoc was condensed to the floor-not-a-pin rationale.build()deliberately does not apply.max(min_protocol_version(network))— the clamp is removed and stays removed (out of scope for the floor restoration). So a pinned-below version is preserved exactly as given (doc: "the pinned version is used as-is; it is not clamped"), while an unpinned build seeds from the per-network floor and ratchets upward monotonically via auto-detect.version_pinned. Collapses the opposite-polarity pair (version_explicit+auto_detect_protocol_version) into one consistently-polarised flag (true= pinned, auto-detect off). The builder'sversionfield also becameOption<&'static PlatformVersion>(defaulting toNoneinstead of a seeded constant). Internal rename — 21 references, none of the old names remain.refresh_protocol_versionis inlined intosdk.rsand the dedicatedsdk/refresh.rsmodule is deleted (−105 lines). It has no production caller in this PR — the init call sites live in feat(sdk): refresh protocol version on SDK init (FFI/WASM/JS) #3902; three#[cfg(test)]unit tests exercise it here.Testing
cargo build -p dash-sdk,cargo fmt -p dash-sdk --check,cargo clippy -p dash-sdk --all-targets --features mocks— clean (zero warnings).cargo test -p dash-sdk --features mocks --lib— 143 passed;cargo test -p dash-sdk --features mocks --test main fetch::document_query_v0_v1— 10 passed. The floor-targeted unit tests assert againstmin_protocol_version(network)directly (floor-agnostic, survive future floor changes);sdk_builder_default_seeds_atomic_to_floorboots a default (Mainnet) SDK and still expectsPROTOCOL_VERSION_11.CI reconciliation
wasm-sdkWasmSdkBuilderbuilder-chaining tests (withVersion()/ multiple-method chaining) —greaterThan(1)→equal(1), because a pinned version is no longer clamped to the floor (depends on the removed clamp, not on the floor value).tests/fetch/common.rsand thesdk_builder_default_seeds_atomic_to_floorcomment — doc-comment wording aligned with the per-network floor semantics (no logic change).Breaking changes
DEFAULT_INITIAL_PROTOCOL_VERSIONconstant (waspub). External code referencing it will no longer compile.SdkBuilder::with_initial_versionfrompub(crate)topub(additive).with_version()now honours the version exactly as given, including a pin below the floor. (The per-network seed values themselves are unchanged: Mainnet → v11, others → v12.)with_version()signature is unchanged;version_pinnedandmin_protocol_versionremain internal.Checklist
cargo build/cargo fmt --check/cargo clippy --all-targets --features mocks).dash-sdklib: 143;document_query_v0_v1: 10).Related
refresh_protocol_versioninto the SDK init paths (FFI / WASM / JS). Provides the production behaviour that eagerly refreshes the version on init; builds on the unifiedversion_pinnedflag and the co-located refresh primitive from this PR; intended to land together.🤖 Co-authored by Claudius the Magnificent AI Agent
Summary by CodeRabbit
New Features
Refactor