Skip to content

fix(sdk)!: version the non-unique identity lookup so 4.1 clients keep working - #5515

Merged
shumkov merged 43 commits into
v5.0-devfrom
fix/legacy-identity-discovery
Oct 23, 2026
Merged

shumkov merged 43 commits into
v5.0-devfrom
fix/legacy-identity-discovery

Conversation

@lklimek

@lklimek lklimek commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Basic explanation

What this does: Gives each proof shape of getIdentityByNonUniquePublicKeyHash its own request/response version, so 4.1.x clients, the 5.0 betas up to beta.4 and current SDKs all work against 4.1.x nodes and against nodes from this release on. V0 is again exactly the 4.1.1 wire shape (separate index and identity proofs) and every node serves it at every protocol version. V1 is new and carries the single merged proof; nodes accept it from protocol 14. The SDK sends V1 only after it has verified a protocol 14 answer.

Value: 4.1.x clients and the published dashwallet-ios App Store builds (9.1.1–9.1.3) keep discovering identities through the 5.0 rollout and after protocol 14 activates on mainnet. Current SDKs get the merged proof once the network has proven it serves it.

Risks: Read-only query behaviour only; no consensus or stored-state change. On testnet (already at protocol 14) V0 answers move from field 4 back to field 2, so SDKs from 5.0.0-beta.5 to rc.7 lose this lookup there and must update (see Breaking Changes). A node that has not reached the protocol 14 activation block refuses V1, and each refusal bans it again, for longer each time, until it catches up and answers.

Issue being fixed or feature implemented

#5361 changed V0 in place from two proofs (field 2) to one merged proof (field 4) at every protocol version. 4.1.x nodes still answer in field 2 and 4.1.x clients only read field 2, so each side broke against the other. This PR's first version restored the 4.1.1 code but kept one V0 envelope carrying both shapes, switched by the producer's protocol version through an extra handler slot. Ivan rejected that shape: different shapes need different request and response versions.

Builds on #5541 (merged), which fixed the operation proofs for BroadcastStateTransition signed by older and newer protocol versions. That part has left this PR; v5.0-dev is merged in, so this diff is the identity lookup only.

What was done?

Proto (platform.proto).

  • Request: v0 = 1 (unchanged), v1 = 2 (new, same fields).
  • Response V0: oneof result { IdentityResponse identity = 1; IdentityProvedResponse proof = 2; }, reserved 4. Byte-for-byte the 4.1.1 shape, including the variant name, so the generated JS/ObjC/Python APIs and serde keys match 4.1.1 too.
  • Response V1: oneof result { IdentityResponse identity = 1; Proof proof = 2; }.
  • The response no longer derives VersionedGrpcResponse (its V0 proof is not a Proof), as in 4.1.1. All published clients regenerated with the pinned toolchain.

Versions (rs-platform-version).

  • Protocol 14's query table accepts request V0 and V1 (min 0, max 1, default 1). Protocols 1–13 accept V0 only, as 4.1 nodes do.
  • The handler-generation slot this PR had added is removed; so are its protocol 14 bumps of the prove/verify slots (back to 0, as on v5.0-dev).
  • New …_two_proofs prove/verify slots, 0 in every table.

Drive.

  • Base names keep the single proof with their v5.0-dev bodies, untouched.
  • lklimek's restored 4.1.1 producer and the strictly guarded 4.1.1 decoder live under prove_/verify_full_identity_by_non_unique_public_key_hash_two_proofs.
  • Removed: the legacy/current proof enums, their 0 | 1 dispatch, the v1/ copies and the unused unbounded query builder.

drive-abci. The handler dispatches on the request version after the bounds check, as getDocuments does: V0 → the 4.1.1 handler over the two-proof producer, V1 → the single-proof handler.

Verifier (FromProof). The response version must equal the request version (ResponseDecodeError otherwise); V0 → two-proof verifier, V1 → single-proof verifier. The signature covers the state, not the envelope, so the client's own request decides the shape. The check that derived the format from the signed version is gone. Query rules still follow the signed producer version, and versions newer than the SDK use the newest known rules.

SDK request selection. A refusal bans the node for every method, and V0 is served everywhere, so the encoder sends V1 only when both the stored protocol version and the highest version this SDK has seen in a verified, signed answer select it. Until something is verified it sends V0, whatever the seed, pin or persisted version. The verified version is recorded with fetch_max after proof, signature and freshness checks, is never seeded or pinned, and is shared between clones. FFI, JNI, Swift, Kotlin, wasm-sdk, js-evo-sdk and the masternode locator all go through this encoder and need no change.

Unchanged from earlier in this PR: the restored 4.1.1 bodies and their strict guards, the newer-protocol fallback, the recorded mainnet vectors and the review hardening. The identity discovery tests now sign their answers with #5541's shared test harness (tests/signed_response).

Compatibility:

Client 4.1.2 node @13 (mainnet) rc.4–rc.7 node @14 (testnet today) this @13 this @14
4.1.x (V0, field 2; verifies at 11–13) ✅ ❌ (today) ✅ ✅
4.2/5.0 beta.1–4, App Store 9.1.1–9.1.3 ✅ ❌ (today) ✅ ✅
5.0 beta.5–rc.7 (field 4) ❌ (today) ✅ ❌ ❌, must update
this SDK ✅ V0 ❌ until testnet runs this release ✅ V0, even if seeded or pinned at 14 ✅ V0, then V1 once 14 is verified

How Has This Been Tested?

Local, macOS (pasta), at c15b778f8a (after #5541 and v5.0-dev were merged in and the review fixes below were applied):

Suite Result
drive-proof-verifier identity_discovery (both versions, tamper/relabel/absence substitution, mainnet PV13 replay) 13 passed, 1 ignored (exporter)
drive-proof-verifier lib non_unique 10 passed
dash-sdk lib identity_discovery_tests (V0 then V1, seeded/pinned V0 on older networks, learning, mock expectations) 8 passed
dash-sdk lib signed_version_tests 16 passed
dash-sdk lib platform::types::identity::tests (the cross-table invariant and selection table) 3 passed
dash-sdk main identity (offline vectors: page 0 V0, pages 1–3 V1; recorded 5.0-beta PV14 two-proof answers now verify) 21 passed, 3 ignored (network-only)
dash-sdk proof_options 93 passed
drive lib two_proofs 6 passed
drive-abci lib handler identity_by_non_unique (V0 at 12/13/latest, V1 at latest, V1 refused at 12/13) 14 passed
drive-abci nonunique_merged_proof (real transport, signed answers through FromProof, both shapes, WASM fixture check) 12 passed
dapi-grpc Rust wire test 3 passed

The identity discovery exporter now also needs DASH_SDK_EXPORT_NONUNIQUE_VECTORS=1; with it, it rewrites byte-identical vectors. The WASM fixture check passes with a final newline added to the fixture and fails when a proof value changes.

Static: cargo check --workspace --all-targets, CI-flag clippy (--workspace --all-targets --all-features --locked -- --no-deps -D warnings), cargo fmt --check --all: all pass.

Run earlier at 919855507a and not repeated here: drive non_unique_public_key_hash 30, drive-proof-verifier lib 356, dash-sdk lib 344, dash-sdk main 146 (+15 network-only ignored), dapi-grpc JS wire tests 47 (all four JS clients), platform-version 27, wasm-drive-verify identity lib on wasm32 4. Clients were regenerated with yarn workspace @dashevo/dapi-grpc build (pinned toolchain).

Older clients against this branch's answers (out-of-tree replays, at 919855507a; the V0 path has not changed since). V0 wire bytes captured from this branch's real gRPC server at protocols 12, 13 and 14 (9 cases each: first match, pagination, cursor before/between/past, exhaustion, unknown key, unknown key with cursor), re-signed, then verified by the unmodified client FromProof of each release:

Client code SDK verifier versions Result
v4.1.1 11 (mainnet seed), 12, 13 27/27 accepted; prost re-encodes the server bytes exactly; every wrong-root control refused; unproved answers decode
a35c4ce8 (5.0.0-beta.4, App Store 9.1.3) 13, 14 27/27
e826b8f9 (App Store 9.1.2) 13, 14 27/27

So 4.1.x clients and the published App Store builds keep discovering identities from these nodes at protocol 13 and after protocol 14 activates.

Mutation checks (at 919855507a; each mutant applied, the named tests went red, source restored byte-identical and green again):

  • selector by the stored version only, or ignoring the verified version → the cross-table invariant, the selection table and the protocol-13-network fetch test;
  • verified version never recorded / recorded with a plain store / not shared across clones → the V0-then-V1 fetch, monotonic-learning and newer-version tests;
  • mock expectations recorded as verified → the up-front-expectations test;
  • FromProof pairing check removed → pairing tests in the verifier (unit + integration), drive-abci and the SDK;
  • protocol 12–13 table accepting V1 → handler and transport refusal tests;
  • protocol 14 table dropping V0 → handler V0 tests, 7 transport/signed tests and the SDK invariant;
  • two-proof strict guards bypassed → the guard tamper tests in both crates and the altered mainnet answer (the 4.1.1 decoder alone accepts it).

Forward merge into v5.1-dev (throwaway trial merge of 919855507a into 4545b88cb5, LATEST 15; not pushed, deleted): one mechanical conflict in rs-sdk/src/mock/sdk.rs (v5.1 adds time_ms to the mock metadata; keep both), and rs-drive-proof-verifier/tests/identity_discovery.rs needs the v5.1 BLS API (dpp::bls::SecretKey, sign(&digest), to_bytes()). With those, every identity-lookup suite above passes at protocol 15. One document-outcome test (document_outcome::should_verify_document_outcome_signed_by_an_unknown_newer_version_with_newest_rules) fails there with unsupported property type: bytes from newer v5.1-dev contract validation; that test came from #5541 and is not part of the identity lookup.

Live, read-only (mainnet, 4.1.2 nodes at protocol 13): identity_discovery_live::should_discover_mainnet_identity passes for 6 key hashes through this SDK (V0, two proofs, height 456794). A raw V1 request to the same nodes is refused with UNKNOWN "decoding error: could not decode identity by public key non unique hash query", which is why the SDK sends V0 until it has verified a protocol 14 answer.

Reviews. The design spec went through two multi-agent review rounds, and the code through four independent reviewers (proof soundness, conventions, test coverage, compatibility/docs). 919855507a then had two more independent reviews: an Opus /code-review at max effort (10 finder angles plus verification) and an adversarial Sol (Codex) review. Neither found anything blocking. Neither found a proof-soundness hole in either shape or any request/response version confusion. Both confirmed that V0 matches 4.1.1 on the wire and that the version tables match the design. Fixes applied after them:

  • the wasm-drive-verify README says the direct verifier takes only a V1 proof, and that a …WithProofInfo proof from a V0 answer is the index proof alone;
  • this description and the book say that a node behind the activation block is banned again on each refusal until it catches up, not once;
  • doc fixes for the two-proof identity decoder (what it does not check), SdkBuilder::with_version (a pin alone may not select a newer request version) and the SDK vector comment (page 0 is V0, pages 1–3 are V1);
  • the WASM fixture check compares parsed JSON instead of bytes;
  • the identity discovery exporter needs an env var as well as --ignored.

Follow-ups, not in this PR:

  • decode the V0 identity from the strict pass instead of verifying the identity proof a second time under the producer's tables;
  • report a V0 identity-proof error with the identity proof's bytes rather than the index proof's (4.1.1 does the same);
  • make the direct WASM verifier read a producer version above its latest with the newest rules, as FromProof does;
  • a root-stable retry for the two-proof producer (a commit between its two reads makes the roots differ and the answer is refused, as in 4.1.x);
  • live read-only checks against testnet V1, once testnet nodes run this release.

In-place changes to shipped generations

Compared with stable 4.1.1:

  • The base-named prove_/verify_full_identity_by_non_unique_public_key_hash v0 mean one proof, not two. That change shipped in the 5.0 prereleases and stays. It cannot be reached at protocol 13 or below: only the V1 handler calls the producer and the bounds refuse V1 there; the verifier is client-side.
  • Handler v0 is identical to 4.1.1 again, apart from calling the producer under its new …_two_proofs name.
  • DRIVE_ABCI_QUERY_VERSIONS_V2 (protocol 14) has its bounds widened to accept V1.

Protocol 13 (stable, mainnet-active) is back to the 4.1.x behaviour: the same wire shape and producer code answer V0 with two proofs, and V1 is refused (UNKNOWN, as 4.1 nodes refuse it by decoding). The proof bytes are not claimed to be identical to a 4.1.2 node's, since the GroveDB revisions differ; what is shown is that the unmodified 4.1.1, 9.1.2 and 9.1.3 FromProof accept this branch's answers (see testing), and that the recorded mainnet protocol 13 answers still verify.

Protocol 14 is not released stable but is active on testnet (since height 623038, under #5361-era builds). Ivan approved this query-only exception: there, V0 answers move from field 4 back to field 2 and V1 is added. No changed table or method is read during block execution, so the "cannot modify consensus" test holds. Adding the new …_two_proofs slots at 0 to every table is ordinary practice, not an in-place edit.

Breaking Changes

None at the consensus level. The ! marks these API and wire breaks:

  • Generated API: the Rust type of get_identity_by_non_unique_public_key_hash_response_v0::Result::Proof is IdentityProvedResponse again (it was Proof from 5.0.0-beta.5 to rc.7), and GetIdentityByNonUniquePublicKeyHashResponse no longer derives VersionedGrpcResponse or VersionedGrpcMessage (no generic proof()/metadata(), no From<…ResponseV0>). Both request and response Version enums gain a V1 variant, which breaks exhaustive matches. The generated JS/ObjC/Python V0 API matches 4.1.1 again; V1 messages are new.
  • Prerelease wire break: SDKs from 5.0.0-beta.5 to rc.7 (npm js-evo-sdk prereleases, the unpublished 9.1.4 TestFlight builds, git pins) read the proof from V0 field 4, which no node built from this sends. Against such nodes their lookups fail as a missing proof and ban the node. Update to this release (rebuild 9.1.4 on it before submitting).
  • dash_sdk::platform::QuerySettings gains the public field verified_protocol_version; struct literals must set it (0 means nothing verified yet).
  • Proof info for V0 answers: fetch_with_metadata_and_proof and the wasm/JS …WithProofInfo calls return the signed index proof for a V0 answer, as 4.1.1 did; on rc.7 they returned the complete single proof. A full offline replay of a V0 answer needs both blobs; the direct WASM verifier verifyFullIdentityByNonUniquePublicKeyHash takes only a V1 proof and cannot replay that index proof (its README says so).
  • Drive (relative to 4.1.1): the base-named prove_/verify_full_identity_by_non_unique_public_key_hash work on the single proof (unchanged from v5.0-dev); the 4.1.1 two-proof producer and verifier are now …_two_proofs.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Original work by @lklimek (restored 4.1.1 producer, decoder, handler and strict guards, and the mainnet vectors; the document-outcome fix, also by @lklimek, shipped in #5541); reworked into versioned envelopes by @shumkov with Claude.

🤖 Generated with Claude Code

PR Hygiene · c15b778

  • Bots — coderabbitai not yet · thepastaclaw not yet — /skip-bots proceeds without the ones not yet reported
  • Self-review — post /self-reviewed
  • Build running
  • Approvals
    • files with no dedicated owner (book/src/sdk/identity-keys.md, book/src/versioning/feature-versions.md, packages/dapi-grpc/build.rs and 47 more) — QuantumExplorer or shumkov
    • rs-drive-abci (packages/rs-drive-abci/src/query/identity_based_queries/identity_by_non_unique_public_key_hash/mod.rs, packages/rs-drive-abci/src/query/identity_based_queries/identity_by_non_unique_public_key_hash/v0/mod.rs, packages/rs-drive-abci/src/query/identity_based_queries/identity_by_non_unique_public_key_hash/v1/mod.rs and 1 more) — QuantumExplorer or shumkov
    • rs-drive (packages/rs-drive/src/drive/identity/fetch/prove/mod.rs, packages/rs-drive/src/drive/identity/fetch/prove/prove_full_identity_by_non_unique_public_key_hash_two_proofs/mod.rs, packages/rs-drive/src/drive/identity/fetch/prove/prove_full_identity_by_non_unique_public_key_hash_two_proofs/v0/mod.rs and 5 more) — QuantumExplorer or shumkov
    • rust-sdk — you own it

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

Summary by CodeRabbit

  • New Features
    • Identity lookups by non-unique public-key hash now support request versions V0 and V1. V1 uses a single proof and is available on protocol 14; V0 remains available for compatibility with older protocols and clients.
    • The SDK selects a compatible lookup version based on verified protocol information and continues to verify signed responses from supported and newer protocol versions.
  • Documentation
    • Updated identity lookup and proof-verification guides to explain version selection, response formats, and compatibility.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between b6017d5 and 9198555.

⛔ Files ignored due to path filters: 14
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/newer-v0-0.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/newer-v1-0.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv12-v0-0.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv12-v0-1.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv12-v0-2.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv13-v0-0.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv13-v0-1.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv13-v0-2.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv14-v0-0.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv14-v0-1.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv14-v0-2.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv14-v1-0.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv14-v1-1.bin is excluded by !**/*.bin
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/pv14-v1-2.bin is excluded by !**/*.bin
📒 Files selected for processing: 55
  • book/src/sdk/identity-keys.md
  • book/src/versioning/feature-versions.md
  • packages/dapi-grpc/build.rs
  • packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m
  • packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/dapi-grpc/test/unit/nonunique-proof.spec.js
  • packages/dapi-grpc/tests/nonunique_identity_lookup_wire.rs
  • packages/rs-drive-abci/src/query/identity_based_queries/identity_by_non_unique_public_key_hash/mod.rs
  • packages/rs-drive-abci/src/query/identity_based_queries/identity_by_non_unique_public_key_hash/v0/mod.rs
  • packages/rs-drive-abci/src/query/identity_based_queries/identity_by_non_unique_public_key_hash/v1/mod.rs
  • packages/rs-drive-abci/tests/nonunique_merged_proof.rs
  • packages/rs-drive-proof-verifier/src/proof.rs
  • packages/rs-drive-proof-verifier/tests/identity_discovery.rs
  • packages/rs-drive-proof-verifier/tests/identity_discovery/mainnet.rs
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/README.md
  • packages/rs-drive/src/drive/identity/fetch/prove/mod.rs
  • packages/rs-drive/src/drive/identity/fetch/prove/prove_full_identity_by_non_unique_public_key_hash_two_proofs/mod.rs
  • packages/rs-drive/src/drive/identity/fetch/prove/prove_full_identity_by_non_unique_public_key_hash_two_proofs/v0/mod.rs
  • packages/rs-drive/src/drive/identity/mod.rs
  • packages/rs-drive/src/verify/identity/mod.rs
  • packages/rs-drive/src/verify/identity/verify_full_identity_by_non_unique_public_key_hash_two_proofs/mod.rs
  • packages/rs-drive/src/verify/identity/verify_full_identity_by_non_unique_public_key_hash_two_proofs/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/v9.rs
  • packages/rs-platform-version/src/version/v14.rs
  • packages/rs-sdk/src/mock/sdk.rs
  • packages/rs-sdk/src/platform/contract_moderation.rs
  • packages/rs-sdk/src/platform/query_settings.rs
  • packages/rs-sdk/src/platform/types/epoch.rs
  • packages/rs-sdk/src/platform/types/identity.rs
  • packages/rs-sdk/src/sdk.rs
  • packages/rs-sdk/src/sdk/identity_discovery_tests.rs
  • packages/rs-sdk/tests/fetch/common.rs
  • packages/rs-sdk/tests/fetch/document_query_v0_v1.rs
  • packages/rs-sdk/tests/fetch/identity.rs
  • packages/rs-sdk/tests/fetch/tokens/token_contract_info.rs
  • packages/rs-sdk/tests/identity_discovery_live.rs
  • packages/rs-sdk/tests/proof_options.rs
  • packages/rs-sdk/tests/vectors/test_fetch_identity_by_non_unique_public_keys/msg_IdentityRequest_0.json
  • packages/rs-sdk/tests/vectors/test_fetch_identity_by_non_unique_public_keys/msg_IdentityRequest_1.json
  • packages/rs-sdk/tests/vectors/test_fetch_identity_by_non_unique_public_keys/msg_IdentityRequest_2.json
  • packages/rs-sdk/tests/vectors/test_fetch_identity_by_non_unique_public_keys/msg_IdentityRequest_3.json
  • packages/rs-sdk/tests/vectors/test_fetch_identity_by_non_unique_public_keys/msg_IdentityRequest_4980414bc9e1d5c39ad7e7ebf5bf7ee40665c3d11fd63cae7be44aebe2862240.json
🚧 Files skipped from review as they are similar to previous changes: 1
  • packages/rs-drive-proof-verifier/tests/vectors/identity-discovery/README.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The pull request adds V1 support for non-unique identity lookup. It defines separate V0 and V1 protobuf responses, adds version-specific query and proof handling, updates SDK request selection, and expands compatibility tests for protocol versions 13 and 14.

Changes: Non-unique identity proof compatibility

Layer / File(s) Summary
Versioned wire contracts
packages/dapi-grpc/protos/..., packages/dapi-grpc/clients/..., packages/dapi-grpc/build.rs
Requests and responses now support V0 and V1. V0 proved responses contain separate index and identity proofs. V1 responses contain one proof. Generated Node.js, web, Objective-C, and protobuf clients support the new oneofs and field layouts.
Version-specific query and proof production
packages/rs-drive-abci/..., packages/rs-drive/..., packages/rs-platform-version/...
V1 requests dispatch to a V1 handler. V0 proof production uses separate proofs. Version tables register the new query and proof methods.
Version-aware proof verification
packages/rs-drive-proof-verifier/..., packages/rs-drive/src/verify/...
Verification matches request and response versions, selects query rules from response metadata, and validates V0 two-proof or V1 single-proof results. State-transition verification separates query-layout selection from verifier version selection.
SDK protocol tracking
packages/rs-sdk/src/platform/..., packages/rs-sdk/src/sdk.rs, packages/rs-sdk/src/sdk/identity_discovery_tests.rs
The SDK records the highest protocol version from fresh, verified responses. Identity lookup selects V1 only when the configured and verified protocol versions support it.
Compatibility and documentation coverage
packages/rs-drive-abci/tests/..., packages/rs-sdk/tests/..., packages/rs-drive-proof-verifier/tests/..., book/src/...
Tests cover transport encoding, pagination, proof tampering, protocol compatibility, live responses, deterministic vectors, and document outcomes. Documentation describes the V0 and V1 proof rules.

Priority: ➖ Normal

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SDK
  participant DAPI
  participant DriveABCI
  participant ProofVerifier
  SDK->>DAPI: Encode V0 or V1 identity lookup
  DAPI->>DriveABCI: Dispatch versioned request
  DriveABCI-->>DAPI: Return two-proof V0 or single-proof V1 response
  DAPI-->>SDK: Return response and signed metadata
  SDK->>ProofVerifier: Verify response and metadata
  ProofVerifier-->>SDK: Return identity or absence
Loading

Suggested reviewers: shumkov

Merge Risk: ⚪ Minimal · up to 91985

This change restores 4.1.1-compatible identity discovery and adds the merged-proof format only for protocol 14 and later. The supplied review evidence shows no remaining blocking issue. The documented break for clients from 5.0.0-beta.5 through rc.7 is an intended tradeoff.

Pre-merge checks: Passed 4 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Docstring Coverage Inconclusive Docstring coverage is 63.87% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 274 functions across 59 files. (11 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
Title check Passed The title clearly identifies the main change: versioning the non-unique identity lookup to preserve compatibility with 4.1 clients.
Full details: Docstring Coverage

Explanation

Docstring coverage is 63.87% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 274 functions across 59 files. (11 skipped: 5 unsupported, 6 too large.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions github-actions Bot added this to the v5.1.0 milestone Oct 21, 2026
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

📖 Book Preview built successfully.

Download the preview from the workflow artifacts.
To view locally: download the artifact, unzip, and open index.html.

Updated at 2026-10-22T20:16:50.705Z

@thepastaclaw

thepastaclaw commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit c15b778) · triage: critical
██████████████░░░░░░ 71% · about 10 min left · running for 25 min
✅ triage → ✅ Phase 2 → ✅ Phase 1 → ⏳ verify 2 → ▫️ publish
Estimated from recent reviews of this tier · updated 22:23 UTC · live progress

@lklimek lklimek modified the milestones: v5.1.0, v5.0.0 Oct 21, 2026 — with ChatGPT Codex Connector
Restore the legacy nested nonunique identity proof response while preserving
current server output and all verifier security, signature and freshness gates.
Backport only the identity-discovery feature commits onto v5.0-dev, adapting
fixture signing to its existing BLS API and regenerating latest fixtures at PV14.

Separate signed producer query layout from retained verifier rules for state
transition outcomes. A genuine PV13 document outcome verifies under a retained
PV14 verifier without an invented owner balance; PV14 still requires its balance.
Keep existing Drive callers and all shipped protocol generations unchanged.

Validate current Drive ABCI response codecs, signed proof adversarial cases,
SDK version policy, read-only mainnet/testnet discovery and pinned client output.
Scoped CI clippy, verify-only Drive clippy, rustfmt and wire tests pass.

Original commits: bb5b1ec, 6f40494.

<sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub>

Co-Authored-By: Codex GPT-6 <noreply@openai.com>
@lklimek
lklimek force-pushed the fix/legacy-identity-discovery branch from 6f40494 to 85f1707 Compare October 21, 2026 18:58
@lklimek lklimek changed the title fix(sdk): restore legacy non-unique identity discovery fix(sdk): preserve identity and operation proof compatibility on v5.0 Oct 21, 2026
@lklimek
lklimek changed the base branch from v5.1-dev to v5.0-dev October 21, 2026 18:58
Restore v4.1.1 nonunique identity producer, verifier and combined query-builder
function bodies exactly. Keep the historical verifier private behind complete
index/identity proof checks and the GroveDB V1 security floor. Move the changed
single-proof implementation and bounded-prefix builder into generation 1.

Select producer/verifier/handler generation 1 only in protocol 14 tables. Keep
protobuf request V0 and route the response by committed current protocol state:
PV13 serves legacy field 2; PV14 serves current field 4. Client verification
continues selecting the actual wire encoding, including deployed PV13 current
proofs, without lowering retained verifier rules or retrying failed proofs.

Represent producer formats explicitly and adapt their node/test callers.
Exercise genuine gRPC responses, signed proofs, SDK pins/learning, populated
identity lookup across lock-in/activation/restarts and read-only live networks.
Scoped CI clippy, verify-only Drive clippy, formatting and wasm32 compilation pass.

Direct Rust producer callers now match a legacy/current enum. The current-format
WASM verifier remains source compatible. No persisted schema or consensus
execution generation changes; no release rehearsal or WASM runtime is claimed.

<sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub>

Co-Authored-By: Codex GPT-6 <noreply@openai.com>
@lklimek lklimek changed the title fix(sdk): preserve identity and operation proof compatibility on v5.0 fix(sdk): preserve identity discovery and operation proof compatibility Oct 21, 2026
@shumkov

shumkov commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

Checked the protocol 13 path against a real 4.1.1 SDK: the unmodified 4.1.1 FromProof accepts the 5.0 node's PV12/PV13 field-2 bytes in all 18 cases (match, pagination, cursor before/between/past, exhaustion, absence with and without a cursor), wrong-root controls fail, and field 4 at PV14 is refused as intended. Two things worth changing:

  1. Accept LegacyProof only for handler generation 0. The new SDK currently accepts a field-2 answer whatever the signed protocol version is, so a node could answer a PV14 request in the legacy two-proof format. Tie it to the signed version: reject LegacyProof unless the signed protocol's identity_by_non_unique_public_key_hash_handler generation is 0 (PV ≤ 13), and Proof (field 4) unless it is 1. Around rs-drive-proof-verifier/src/proof.rs:440-453; the test at tests/identity_discovery.rs:276 could cover a PV14-signed legacy answer being refused.

  2. BroadcastStateTransition now hard-fails on signed protocols above 14 (rs-drive-proof-verifier/src/proof.rs:1531). Once PV15 activates, clients on this SDK can no longer verify state-transition results until they upgrade. Is that intended? If not, falling back to the newest known verification rules (as the other proof paths do since fix(platform): verify signed protocol versions and use one identity proof #5361) would keep them working.

shumkov and others added 6 commits October 22, 2026 11:31
…version

A node could answer a protocol 14 identity lookup in the legacy two-proof
format (field 2), or a protocol 13 lookup in the single-proof format
(field 4), and the client verified either. The signed protocol version's
`identity_by_non_unique_public_key_hash_handler` generation now decides:
generation 0 (protocol 13 and earlier) accepts only field 2, generation 1
(protocol 14) only field 4. Anything else is a verification error, and the
answer is never re-read in the other format. The SDK treats it as a proof
error: the request moves to another node, and the refused answer does not
teach the SDK its version.

No live network is affected. Mainnet runs protocol 13 on 4.1.x nodes, which
answer in field 2; testnet runs protocol 14, which answers in field 4.

Tests: signed PV12/PV13 field-4 and PV14 field-2 answers are refused by the
verifier (✖ before the change, ✔ after) and through the SDK. The matching
formats still verify with pagination and proved absence. The SDK replays and
the fixture generator use the format each version emits; regenerated vectors
are byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…own rules

Since signed protocol versions select proof rules, the SDK verifies an answer
signed by an unknown newer protocol with its newest known verifier table. Two
paths still refused such answers outright because they also build the proved
query from the producer's version: state-transition results and non-unique
identity lookups. Once protocol 15 activated, clients on this SDK could no
longer verify broadcast results or discover identities until they upgraded.

The shared query-version helper now reads a version above the newest known
one with the newest known construction rules. A wrong guess can only fail
verification: the proof must still rebuild the root the quorum signed, and the
signature still covers the newer version. The caller's verifier table, which
the SDK never lowers below its stored version, is unchanged. Version 0 is
still refused; reserved mock versions, which sit above the newest one, are read
with the newest rules and never looked up. No other proof path in proof.rs
refused unknown versions; latest-versions contract proofs already fell back to
the verifier table.

Tests (✖ before the change, ✔ after): a PV15-signed document outcome verifies
under PV14 rules and still needs the owner balance, and a PV15-signed field-4
identity answer verifies with pagination. A PV15-signed field-2 answer is
refused, and tampering with the newer version fails the signature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rsion

Clients pick the identity-lookup wire format to accept from the signed
version's handler generation, while the handler builds its answer from the
Drive producer generation. If the two drifted apart in any version table,
that version would fail every proved lookup or have its answers refused.

The test walks every protocol version and requires the handler, producer and
verifier generations to agree. It also pins the deployed formats: protocol 13
and earlier answer with generation 0 (field 2), protocol 14 with generation 1
(field 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The legacy-format tests so far used synthetic proofs from a local Drive. Add
two real answers recorded read-only from mainnet protocol 13 nodes (4.1.x) at
height 456535: a first match for a non-unique key hash, and a proved absence
after the largest identity ID. They are stored with the public key of the
quorum that signed each one.

The offline replay checks the raw protobuf layout: response version 0 carries
result field 2, holding the index proof and, for the match, the separate
identity proof. It then runs full proof and signature verification under the
protocol 13 and newest verifier tables. It also checks that altering the
identity proof, relabelling the answer as protocol 14 or changing the cursor
is refused. An ignored live test regenerates the vectors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on rules

Follow-ups to the format gate and the newest-rules fallback from review:

- Drive ABCI's signed merged-proof tests still sent single proofs signed as
  protocol 12/13 and expected them to verify. They now build each version's
  answer in the format it emits, check the single-proof adversarial cases only
  where that format is legitimate, and expect unknown or reserved versions to
  reach the signature check instead of a decode error.
- Version-tampering cases now relabel an answer to a version that emits the same
  format, so they fail on the signature rather than the format gate, and assert
  `InvalidSignature`. Same for the recorded mainnet answer.
- New SDK-level tests replay an identity answer and a document outcome signed by
  a version newer than the SDK. Both verify with the newest known rules, and the
  SDK does not learn the unknown version. The vectors come from the existing
  deterministic generators; the other vectors regenerate byte-identically.
- The fallback comment no longer overclaims: a wrong guess cannot authenticate
  data outside the signed root, and changed layouts are expected to fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ules

The identity-keys page said a non-unique lookup answer's format was independent
of the protocol version, that protocol 13 nodes could answer in the single-proof
format, and that newer protocols fail closed. Now each signed version accepts
one format (field 2 up to protocol 13, field 4 from 14), and newer versions are
read with the newest known rules. The put-operations page now also covers
outcomes signed by a newer protocol.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shumkov
shumkov marked this pull request as ready for review October 22, 2026 04:50
@shumkov

shumkov commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

@lklimek Ivan asked us to finish this for rc.8, so I pushed six commits on top of yours. Nothing of yours was rewritten.

  1. The format follows the signed version. Field 2 is accepted only when the signed version's handler generation is 0, and field 4 only when it is 1. Anything else is a proof error and is never re-read in the other format. As a result, the PV13 single-proof acceptance is gone. No live network is affected: mainnet is PV13 on 4.1.2 and answers in field 2, testnet is PV14 and answers in field 4. Only an rc node on a PV13 network would now be refused.
  2. Newer protocols are read with the newest known rules. Before, a signed version above 14 was refused. Now broadcast results and identity discovery read it with PV14 rules. The proof must still rebuild the signed root, and the stored-version floor is unchanged.
  3. Hardening. One test now checks that handler, producer and verifier generations agree in every version. Two real mainnet field-2 answers are replayed offline. A few tests were adjusted so tampering is caught by the signature check rather than the format check, and the book is updated.

The wasm-drive-verify legacy binding is skipped: wasm-sdk and js-evo-sdk go through rs-sdk FromProof. The details and test runs are in the description under "Finished by".

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai ✓ · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 22, 2026
shumkov and others added 6 commits October 22, 2026 15:15
…e sentinel

`should_forward_producer_and_verifier_tables_independently` used verifier
generation 1 as its "unknown verifier" sentinel. Protocol 14 now selects
generation 1, so the verifier accepted it and the `expect_err` panicked. The
sentinel and the `UnknownVersionMismatch { received }` assertion now use 255.
The producer-slot success and verifier-slot rejection checks are unchanged.

Test would have caught this in CI if it ran there: ✖ before (panics at the
`expect_err`), ✔ after. The whole identity lib suite (4 tests) passes on
wasm32-unknown-unknown under wasm-bindgen-test-runner. No PR CI job runs this
crate's wasm32 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oves

The SDK replays for answers signed by an unknown newer protocol read
`pv{latest+1}` vectors and the `pv{latest}` contract. On a branch whose latest
version is 15 those files do not exist, and re-running the exporters could not
create them: the document-outcome exporter only writes the protocol 13 and 14
contracts.

The recorded "newer" vectors are now signed by protocol version 1000, far above
any real version, and stored without a version in their name
(`newer-current-0.bin`, `newer-{request,response}.bin`). They are built over the
protocol 14 layout and the document outcome uses `pv14-contract.bin`. The SDK
tests assert that the signed version is still unknown to the build, instead of
computing it. The identity exporter's version list is fixed at 12, 13 and 14,
so re-running it on a later branch rewrites the files the SDK tests read. The
in-process verifier tests keep using latest+1. The existing vectors regenerate
byte-identically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tests

`verify_fetching_quorum_key` completes on its first poll, so `tokio::join!`
always learned the older version before the newer one, and the tests could not
see a downgrade. They now verify the protocol 14 answer, then the older one,
and assert the stored version stays 14 after each step.

Mutation check of `maybe_update_protocol_version`: removing only the
`received_version <= current` guard keeps both tests green, which is correct
because `fetch_max` still prevents the downgrade. Removing the guard and
replacing `fetch_max` with a plain store fails both (✖ 12 and 13 instead of 14);
the restored code passes (✔).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `identity_by_non_unique_public_key_hash_rejects_malformed_legacy_proof` only
  reached the missing-metadata error. It now signs the decoded field-2 answer
  as protocol 13, with an index proof that passes the envelope check over
  garbage bytes, so the legacy verifier itself must refuse it (GroveDB error).
- New: a field-2 answer without its index proof is `NoProofInResult`, even
  when identity bytes are present.
- New: a verified lookup returns the signed proof, which for a legacy answer is
  the index proof, as the book documents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The capture test shares a binary with the read-only live checks, so running
those with `--ignored` silently rewrote the committed mainnet vectors with the
current height, quorum and signature. It now does nothing unless
`DASH_SDK_CAPTURE_MAINNET_VECTORS=1` is set, and says so. The vectors README
gives the full capture command. Checked: without the variable the test skips
and no vector changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tables

The legacy two-proof verifier first checks both proofs strictly, against queries
built from the producer's tables and verified with this verifier's GroveDB
version. It then hands both proofs to the restored v0 decoder, which rebuilt the
identity query from the verifier's tables. Today every GroveDB version merges
that query the same way. A future one that merges it differently would have
rejected every genuine protocol 13 answer, and those errors are retryable, so
honest nodes would have been banned.

The decoder now gets the producer's tables, so both constructions match. The
strict checks before it already applied the verifier's version to the same
bytes, so the security floor is unchanged.

Dropping the second verification instead would have left the restored v0
decoder without a caller, and this PR keeps that body identical to v4.1.1.

No regression test: no two existing GroveDB versions build this query
differently, so the false reject cannot be reproduced. The legacy tamper
tests, the recorded mainnet replay and the Drive and Drive ABCI non-unique
suites pass unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shumkov and others added 6 commits October 22, 2026 21:59
- identity-keys: V0 answers with two proofs at every protocol version,
  V1 with one proof from protocol 14; the response version must match
  the request; how the SDK picks V1 only after verifying a protocol that
  serves it; which older clients keep working.
- feature-versions: the protocol 14 query table excerpt now shows the
  nested non-unique lookup bounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two-proof verifier proves the index entry under the verifier's
GroveDB rules and then lets the 4.1.1 decoder read the identity under
the producer's tables. It compared only their roots; it now also
requires the decoded identity to be the one the index entry names.
Today both read the same bytes with the same queries, so this cannot
be reached by a test; it keeps the two reads from silently diverging if
a GroveDB version ever decodes the same bytes differently.

Also from review: error messages say "two-proof" instead of "legacy"
(V0 is a supported request version), the stray `#[rustfmt::skip]` on the
4.1.1 decoder goes (the body formats unchanged), and a redundant test
import and a dated doc phrase are fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sion

A matched mock expectation answers with invented metadata at the latest
protocol version. It went through the same acceptance as a verified
answer, so it raised the verified protocol version, and a non-unique
lookup registered with `expect_fetch` before an earlier mocked fetch was
keyed in V0 while the SDK then sent V1 and found no expectation. The
mock parser now reports when an expectation answered; that metadata
still moves the stored version as before but is not recorded as
verified. Recording moves out of `verify_response_metadata_as_of` into
the two entry points that take verified metadata, and the public
`verify_response_metadata` documents that it records it.

Test (red before, green after): two lookup pages registered up front
are both answered and the verified version stays 0.

Also: a verified answer of another query switches the lookup to V1; the
network-below-14 test covers protocol 12 pages too; the response
metadata reader is tested for both versions, missing metadata and a
missing version; the reader's import moves to the top.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The answer's shape was encoded as `Option<Option<&[u8]>>` (Some for V0,
with or without identity bytes; None for V1). It is now an explicit
"answered with two proofs" flag next to the identity bytes, so the
pairing check reads as what it means. No behaviour change.

New in-file tests pin the error order for both versions: a proved
answer without metadata is `EmptyResponseMetadata`, a request without a
version is `EmptyVersion`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The mainnet replay asserts why altered answers are refused: a
  truncated identity proof does not decode, a changed byte of the
  identity's own data fails GroveDB's check, and another cursor fails the
  two-proof guard. A two-proof message packed into a V1 proof fails to
  decode as a GroveDB proof.
- The drive-abci exporter builds the rs-sdk and wasm vectors at
  protocol 14 instead of the latest version, so a later branch rewrites
  the same files (on a v5.1-dev trial merge, latest() made it fail).
- The JS and Rust wire tests round-trip V0 identity proof bytes too; the
  Rust wire test file is renamed for what it covers, and the new V1
  handler tests are named `should_…`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Book: 4.1 nodes and every node from 5.0.0-rc.8 on answer V0-only
  clients (the rc.4-rc.7 nodes on testnet do not); restore the caveat
  that an absence answer can verify at an index location a newer
  protocol no longer uses.
- Drive version 9 doc: the two-proof slots are 0 in every drive version,
  so they are no difference from V8.
- Protocol 14 query table doc: "the wire surface is unchanged" refers to
  documents.
- Vectors README: the newer-version vectors are built with protocol 14
  rules and keep verifying while the newest rules build the same query.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shumkov
shumkov marked this pull request as ready for review October 22, 2026 16:02
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai ✓ · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Oct 22, 2026
shumkov and others added 4 commits October 23, 2026 01:22
…identity-discovery

Bring in #5541 (445ea06), which carries the document-outcome fix this
branch had duplicated. Conflicts in the document-outcome files are resolved
to #5541's versions: put-operations.md, the query-version verifier docs and
test in rs-drive, the SDK document-outcome tests, and the comment on
proof_query_platform_version. The identity lookup in proof.rs keeps this
branch's code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The document-outcome tests now live in tests/document_outcome.rs from the
merged operation-proof branch, so drop this branch's copy of them and of
their README pointer. The identity discovery tests take the test quorum,
its signer and NEWER_PROTOCOL_VERSION from tests/signed_response instead of
keeping their own. The exporter rewrites byte-identical vectors.

No behaviour change: test-only refactor (identity_discovery 13 + 1 ignored,
document_outcome 6 + 1 ignored, all passing).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A node that has not reached the activation block refuses every V1 request
it gets, not only the first, and each refusal bans it again with a longer
backoff. The ban count resets once the node answers after catching up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ty-discovery

v5.0-dev now holds #5541 as c20b49b, whose tree equals the #5541 head
merged earlier, so this merge changes no files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shumkov and others added 6 commits October 23, 2026 03:10
The README told callers to replay the non-unique key hash lookup with the
direct verifier. That only works for a V1 answer's single proof. An SDK
sends V0 until it has verified a protocol 14 answer, and for a V0 answer
the proof returned with proof info is the index proof alone, which the
direct verifier cannot check. wasm-sdk and js-evo-sdk have no doc comments
on the proof-info methods, so the README is the only place to say this.

No behaviour change: documentation only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The doc comment called the decoder "the 4.1 verifier, unchanged" and said
its proof checks are not strict. Both of its verify_query calls are strict.
What it lacks are the shape and pairing checks: it ignores the index row's
value, accepts absence alongside an identity proof, and does not bind the
decoded identity to the index entry. The comment now says that and no
longer depends on release history.

No behaviour change: comment only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…quest

The SdkBuilder and proof-parsing docs said a pin governs request
construction. Some requests, such as the non-unique key hash lookup, also
need a verified network version before they use a newer request version,
so an SDK pinned at protocol 14 still sends V0 until it has verified a
protocol 14 answer. Point at QuerySettings::verified_protocol_version.

No behaviour change: documentation only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comment called every recorded page a single-proof vector. Page 0 is a
V0 two-proof answer, because the SDK has verified nothing yet; its signed
protocol 14 metadata makes pages 1-3 V1 single-proof answers.

No behaviour change: comment only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The exporter compared its pretty-printed output with the committed
wasm-drive-verify fixture byte for byte. The committed file has no final
newline while .editorconfig asks for one, so an editor adding it would
fail CI with "single proofs changed" although no proof changed. Compare
parsed serde_json values instead.

Checked by hand: with a final newline appended to the fixture the test
passes; with one proof value altered it still fails with "single proofs
changed".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd an env var

`cargo test -p drive-proof-verifier -- --ignored` rewrote the committed
identity discovery vectors in place, since the exporter was behind
#[ignore] alone. Like the mainnet capture, it now also needs
DASH_SDK_EXPORT_NONUNIQUE_VECTORS=1 and otherwise returns after printing
how to enable it. The vectors README shows the new command.

Checked: with --ignored and no env var the exporter prints "skipped" and
writes nothing; with the env var it rewrites byte-identical vectors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shumkov shumkov changed the title fix(sdk): preserve identity discovery and operation proof compatibility fix(sdk)!: version the non-unique identity lookup so 4.1 clients keep working Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Waiting for bot review — coderabbitai not yet · thepastaclaw not yet. Wait for the missing reviews, or a writer can post /skip-bots to proceed without them; blocking findings still need addressing.
Full checklist in the description.

@shumkov
shumkov merged commit 4f028ff into v5.0-dev Oct 23, 2026
49 of 50 checks passed
@shumkov
shumkov deleted the fix/legacy-identity-discovery branch October 23, 2026 07:19
PastaPastaPasta pushed a commit to thepastaclaw/review-system that referenced this pull request Oct 23, 2026
Capture gh output as bytes and decode at the call boundary, allowing replacement only for PR diffs while keeping API/JSON strict. Small binary blobs can appear as text hunks; preserve Unicode and inline placement rather than dropping the review.

Close running steps and the gate on unexpected worker crashes, just as for classified failures. Add real-subprocess and worker publication regressions for the binary fixture behind dashpay/platform#5515.

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-bots Waiting for the review bots to report on this head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants