Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
85f1707
fix(sdk): preserve legacy proof compatibility on v5.0
lklimek Oct 21, 2026
4f33bf7
fix: preserve historical identity proof generations
lklimek Oct 21, 2026
8b9933e
fix(sdk): accept each non-unique identity proof format only from its …
shumkov Oct 22, 2026
17ed063
fix(sdk): verify proofs signed by a newer protocol with the newest kn…
shumkov Oct 22, 2026
7f7d678
test(drive-abci): pin one non-unique proof generation per protocol ve…
shumkov Oct 22, 2026
f461e52
test(sdk): replay recorded mainnet legacy identity-discovery answers
shumkov Oct 22, 2026
e901123
test: align signed identity-discovery tests with the format and versi…
shumkov Oct 22, 2026
f6f5e1d
docs(book): describe signed-version proof format and newer-protocol r…
shumkov Oct 22, 2026
6335fd7
test(wasm-drive-verify): use an unsupported verifier generation as th…
shumkov Oct 22, 2026
2d2f120
test: keep newer-protocol SDK vectors valid when the latest version m…
shumkov Oct 22, 2026
39cfc10
test(sdk): apply the newer answer first in monotonic version-learning…
shumkov Oct 22, 2026
df10741
test(sdk): cover the legacy decode path and the proof a lookup returns
shumkov Oct 22, 2026
5e98f7d
test(sdk): only rewrite mainnet vectors when explicitly asked
shumkov Oct 22, 2026
baacc6e
fix(drive): decode legacy identity answers with the producer's query …
shumkov Oct 22, 2026
3b2dbe5
docs: correct identity-discovery version notes and restore the 4.1 cl…
shumkov Oct 22, 2026
b6017d5
test(sdk): rewrite mainnet vectors only when the capture variable is 1
shumkov Oct 22, 2026
fda1a83
fix(sdk): verify operation proofs with the layout of the protocol tha…
shumkov Oct 22, 2026
e1c8d85
docs(book): explain which protocol version selects a document-outcome…
shumkov Oct 22, 2026
e07e808
test(sdk): pin which protocol version drives each document-outcome check
shumkov Oct 22, 2026
445ea06
docs(book): say which version drives document-outcome validation
shumkov Oct 22, 2026
49a4e10
feat(platform): version the non-unique identity lookup request and re…
shumkov Oct 22, 2026
85726f9
feat(platform): accept non-unique lookup request V1 from protocol 14
shumkov Oct 22, 2026
bc357a2
refactor(drive): give the restored two-proof lookup its own methods
shumkov Oct 22, 2026
5f042e7
feat(drive-abci): answer non-unique lookups by request version
shumkov Oct 22, 2026
dca309d
fix(sdk): verify a non-unique lookup in the shape its request asked for
shumkov Oct 22, 2026
14c0df7
feat(sdk): send lookup request V1 only after verifying a protocol tha…
shumkov Oct 22, 2026
b922919
test: cover both lookup versions end to end and replay what older cli…
shumkov Oct 22, 2026
296eeaa
docs(book): describe the versioned non-unique identity lookup
shumkov Oct 22, 2026
9827a9a
fix(drive): check the decoded identity against its two-proof index entry
shumkov Oct 22, 2026
064fb0f
fix(sdk): keep made-up mock metadata out of the verified protocol ver…
shumkov Oct 22, 2026
3b205ff
refactor(sdk): name the non-unique answer shape in FromProof
shumkov Oct 22, 2026
eb3337f
test: pin the remaining refusals and keep the SDK vectors at protocol 14
shumkov Oct 22, 2026
9198555
docs: correct which nodes answer older clients and other review notes
shumkov Oct 22, 2026
a3ab7a7
Merge branch 'fix/operation-proof-protocol-versions' into fix/legacy-…
shumkov Oct 22, 2026
fa10996
test: sign identity discovery answers with the shared harness
shumkov Oct 22, 2026
587675b
docs(book): say a node behind protocol 14 is banned until it catches up
shumkov Oct 22, 2026
c58bea5
Merge remote-tracking branch 'origin/v5.0-dev' into fix/legacy-identi…
shumkov Oct 22, 2026
79c740a
docs(wasm-drive-verify): say the direct verifier takes only a V1 proof
shumkov Oct 22, 2026
5845ccc
docs(drive): describe what the two-proof identity decoder does not check
shumkov Oct 22, 2026
aae7a7e
docs(sdk): note that a pinned version alone may not select a newer re…
shumkov Oct 22, 2026
f2d7ed9
test(sdk): say which non-unique lookup vectors are two-proof answers
shumkov Oct 22, 2026
e31ef7b
test(drive-abci): compare the WASM single-proof fixture as parsed JSON
shumkov Oct 22, 2026
c15b778
test(drive-proof-verifier): gate the identity discovery exporter behi…
shumkov Oct 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 46 additions & 17 deletions book/src/sdk/identity-keys.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,25 +444,54 @@ let identity_ids = drive.fetch_identity_ids_by_non_unique_public_key_hash(

`getIdentityByNonUniquePublicKeyHash` returns the first matching identity in
lexicographic identity-ID byte order. `start_after` is exclusive; use the returned
ID to fetch the next match. A proved response contains one standard `Proof`
(result field 4). It proves the complete index prefix through that identity and
all its keys, balance and revision at the same signed root. An absent hash or
exhausted cursor proves the entire remaining range is empty. A missing identity
referenced by the index is a proof error, rather than an empty result.
ID to fetch the next match. The request version chooses the shape of a proved
answer:

| Request | Proved answer | Served from |
|---|---|---|
| V0 | Separate index and identity proofs (`IdentityProvedResponse`, result field 2), as 4.1 nodes send | every protocol version |
| V1 | One standard `Proof` (result field 2 of response V1) | protocol 14 |

The V0 index proof proves exactly the first index entry after the cursor, or that
there is none; the identity proof proves that identity's keys, balance and revision.
Both must have the same root, and an identity proof without an index entry, or an
index entry without its identity, is a proof error. The V1 proof proves the complete
index prefix through that identity and all its keys, balance and revision at one
root. In both shapes an absent hash or exhausted cursor proves the remaining range
is empty, and a missing identity referenced by the index is a proof error, rather
than an empty result. Unproved answers (result field 1) are the same in both
versions.

The response version must equal the request version. The quorum signature covers
the state, not the envelope, so the SDK refuses an answer of the other version
instead of reinterpreting it, and the request moves to another node. For a V0
answer the signed proof is the index proof; `fetch_with_metadata_and_proof` returns
it, and independent replay of the full verification needs both original blobs.

Clients reconstruct the query using the producer protocol version in signed
metadata and retain their verification security floor. Unsupported future query
versions require an SDK update and fail closed. The Rust SDK still returns
`Option<Identity>`; high-level WASM/JavaScript APIs retain their existing result
shape. The direct WASM verifier takes one proof blob and returns a root that the
caller must authenticate independently.

The nested double-proof response (retired field 2) has been removed with no
fallback. Stable v4.1.1 clients and nodes use that old format and are incompatible
with this proved endpoint during a mixed rollout. Update clients and nodes
together; mismatched or unsupported-future-version responses can trigger the
existing SDK retry and node-ban behavior. Unproved response field 1 and the
request fields remain unchanged.
metadata and retain their verification security floor. A producer version newer
than the SDK is read with the newest query rules the SDK knows; the proof must
still rebuild the signed root. An absence answer can still verify at an index
location a newer protocol no longer uses, so relocating this index needs an SDK
update. The Rust SDK still returns `Option<Identity>`;
high-level WASM/JavaScript APIs retain their existing result shape. The direct
WASM verifier takes one V1 proof blob and returns a root that the caller must
authenticate independently.

**How the SDK picks the request version.** A node that refuses a request version
is banned for every method, so the SDK sends V1 only when two versions both select
it: its stored protocol version, and the highest protocol version it has seen in a
verified, signed answer. Until it has verified one, it sends V0, which every node
serves. A seeded, pinned or persisted version alone therefore never sends V1 to a
network that may still run protocol 13. On a network that has just activated
protocol 14, a node that has not reached the activation block yet refuses V1.
Each refusal bans it again, for longer each time, until it catches up and answers.

**Older clients.** 4.1.x clients and 5.0 betas up to beta.4 send only V0 and read
only result field 2, so 4.1 nodes and every node from 5.0.0-rc.8 on answer them,
before and after protocol 14 activates. The 5.0 prereleases from beta.5 to rc.7
sent V0 and expected the proof at field 4, which nodes from rc.8 on no longer send;
they must update.

**Fetch all keys for an identity:**
```rust
Expand Down
10 changes: 9 additions & 1 deletion book/src/versioning/feature-versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,10 +490,18 @@ diff:
```rust
// packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v2.rs

/// Differs from v1 in two slots.
/// Differs from v1 in three slots.
/// `document_query_helpers.compute_aggregate_mode_and_check_limit` is 2
/// rather than 0: the ranked and boolean-`HAVING` routing gate. ...
pub const DRIVE_ABCI_QUERY_VERSIONS_V2: DriveAbciQueryVersions = DriveAbciQueryVersions {
identity_based_queries: DriveAbciQueryIdentityVersions {
identity_by_non_unique_public_key_hash: FeatureVersionBounds {
min_version: 0,
max_version: 1,
default_current_version: 1,
},
..DRIVE_ABCI_QUERY_VERSIONS_V1.identity_based_queries
},
document_query_helpers: DriveAbciDocumentQueryHelperVersions {
compute_aggregate_mode_and_check_limit: 2,
},
Expand Down
11 changes: 8 additions & 3 deletions packages/dapi-grpc/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,11 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
// - "GetConsensusParamsResponse"
// - "GetStatusResponse"
//
// The following responses are excluded as they need custom proof handling:
// - "GetIdentityByNonUniquePublicKeyHashResponse" (V0 carries two proofs)
//
// "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests
const VERSIONED_RESPONSES: [&str; 67] = [
"GetIdentityByNonUniquePublicKeyHashResponse",
const VERSIONED_RESPONSES: [&str; 66] = [
"GetContractModerationStatusResponse",
"GetContractModerationEntriesResponse",
"GetContractDocumentRemovalsResponse",
Expand Down Expand Up @@ -283,7 +285,10 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig {
// - Bumping the matching `FeatureVersionBounds.max_version`
// to 1 in `rs-platform-version`.
// - Implementing the v1 dispatch arm in `drive-abci`.
const VERSIONED_AT_V1_REQUESTS: [&str; 1] = ["GetDocumentsRequest"];
const VERSIONED_AT_V1_REQUESTS: [&str; 2] = [
"GetDocumentsRequest",
"GetIdentityByNonUniquePublicKeyHashRequest",
];
const VERSIONED_AT_V1_RESPONSES: [&str; 1] = ["GetDocumentsResponse"];

// Derive VersionedGrpcMessage on requests
Expand Down
Loading
Loading