Skip to content

feat(drive): add document history retrieval#3725

Open
PastaPastaPasta wants to merge 3 commits into
v3.1-devfrom
codex/document-history-retrieval
Open

feat(drive): add document history retrieval#3725
PastaPastaPasta wants to merge 3 commits into
v3.1-devfrom
codex/document-history-retrieval

Conversation

@PastaPastaPasta
Copy link
Copy Markdown
Member

@PastaPastaPasta PastaPastaPasta commented May 21, 2026

Issue being fixed or feature implemented

Adds an end-to-end public read path for document history when documentsKeepHistory is enabled. Today Drive stores historical revisions, but SDK users cannot retrieve them through DAPI / Evo SDK APIs.

What was done?

  • Added getDocumentHistory to DAPI proto and Rust gRPC transport.
  • Added Drive document-history fetch/prove/verify APIs over the existing keep-history subtree.
  • Added Drive ABCI query handling with ID and pagination validation.
  • Added proof-verifier support for timestamp-keyed DocumentHistory.
  • Exposed document-history queries through rs-sdk, wasm-sdk, and js-evo-sdk.
  • Added focused Drive history tests and js-evo-sdk facade forwarding tests.

How Has This Been Tested?

  • cargo check -p dapi-grpc -p platform-version -p drive -p drive-abci
  • cargo check -p drive-proof-verifier -p rs-dapi-client -p dash-sdk -p wasm-sdk
  • cargo check -p drive-abci
  • cargo test -p drive document_history -- --nocapture
  • PATH="/opt/homebrew/opt/llvm/bin:$PATH" CC_wasm32_unknown_unknown="/opt/homebrew/opt/llvm/bin/clang" CXX_wasm32_unknown_unknown="/opt/homebrew/opt/llvm/bin/clang++" yarn workspace @dashevo/wasm-sdk build
  • yarn workspace @dashevo/evo-sdk build
  • yarn workspace @dashevo/evo-sdk test:unit

Breaking Changes

None.

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

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

This pull request was created by Codex.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added document history query capability to retrieve historical revisions of documents with pagination support (limit, offset) and time-based filtering
    • Introduced document history endpoints with optional cryptographic proof verification
    • Added JavaScript SDK methods getDocumentHistory() and getDocumentHistoryWithProofInfo() for accessing document historical data

Review Change Stack

@github-actions github-actions Bot added this to the v3.1.0 milestone May 21, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

This PR introduces a complete document history query feature spanning gRPC protocol definitions, Drive storage operations, proof generation/verification, and SDKs. Adds the getDocumentHistory RPC endpoint with versioned request/response types, implements document history fetching with timestamp-keyed pagination and proof support in Drive, and exposes the feature through Rust/WASM/JavaScript SDKs.

Changes

Document History Query & Proof Implementation

Layer / File(s) Summary
Proto & gRPC Service Setup
packages/dapi-grpc/protos/platform/v0/platform.proto, packages/dapi-grpc/build.rs, packages/rs-dapi-client/src/transport/grpc.rs
Adds getDocumentHistory RPC and GetDocumentHistoryRequest/GetDocumentHistoryResponse protobuf messages with versioned fields for contract/document identification, pagination, timestamp filtering, and proof mode.
Drive Document History Query Implementation
packages/rs-drive/src/drive/document/query/..., packages/rs-drive/src/drive/document/get_fetch/fetch_document_history/..., packages/rs-drive/src/drive/document/mod.rs, packages/rs-drive/src/error/drive.rs
Implements fetch_document_history_query_v0 to build GroveDB path queries with timestamp-based range filtering, fetch_document_history_v0 to deserialize documents into timestamp-keyed BTreeMap, and validate_document_history_limit to enforce MAX_DOCUMENT_HISTORY_FETCH_LIMIT bounds.
Drive Document History Proof Generation
packages/rs-drive/src/drive/document/prove/prove_document_history/...
Adds prove_document_history and prove_document_history_v0 to generate cryptographic proofs of document history state via grove_get_proved_path_query.
Query Service Endpoint Handler
packages/rs-drive-abci/src/query/document_history/..., packages/rs-drive-abci/src/query/service.rs
Implements query_document_history and query_document_history_v0 to validate and dispatch document history requests, handles both fetch and proof modes, and wires the get_document_history gRPC endpoint.
Drive Document History Verification
packages/rs-drive/src/verify/document/verify_document_history/...
Adds verify_document_history_v0 to validate document history proofs by replaying the query against proven GroveDB state and decoding returned documents.
Proof Verifier Integration
packages/rs-drive-proof-verifier/src/proof.rs, packages/rs-drive-proof-verifier/src/types.rs
Implements FromProof for GetDocumentHistoryRequest to verify document history proofs and cryptographic signatures, adds DocumentHistory type alias for timestamp-keyed history results.
Platform Version Management
packages/rs-platform-version/src/version/drive_abci_versions/..., packages/rs-platform-version/src/version/drive_versions/..., packages/rs-platform-version/src/version/mocks/v2_test.rs
Adds version tracking fields to DriveAbciQueryVersions, DriveDocumentQueryMethodVersions, DriveVerifyDocumentMethodVersions across protocol versions v1/v2/v3, initialized to version 0.
Rust SDK Integration
packages/rs-sdk/src/platform/documents/document_history_query.rs, packages/rs-sdk/src/platform/query.rs, packages/rs-sdk/src/platform/fetch.rs
Introduces DocumentHistoryQuery type with contract/document IDs and pagination fields, implements Query<GetDocumentHistoryRequest> and Fetch<DocumentHistory> traits to wire SDK clients to gRPC endpoints.
WASM SDK Integration
packages/wasm-sdk/src/queries/document.rs
Adds wasm-bindgen methods getDocumentHistory and getDocumentHistoryWithProofInfo with embedded TypeScript type definitions, supporting proof-mode responses via ProofMetadataResponseWasm.
JavaScript SDK Facade
packages/js-evo-sdk/src/documents/facade.ts, packages/js-evo-sdk/tests/unit/facades/documents.spec.ts
Exposes history() and historyWithProof() methods on DocumentsFacade as async wrappers around WASM SDK calls, with corresponding unit tests validating stub invocations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • dashpay/platform#3711: Both PRs touch packages/rs-sdk's platform/query.rs/platform/fetch.rs Query/Fetch wiring; the retrieved PR refactors Query (via QueryContext) and Fetch trait models that the main PR builds upon for DocumentHistoryQuery integration.

Suggested labels

dapi-endpoint

Suggested reviewers

  • shumkov
  • QuantumExplorer

Poem

🐰 A history of documents, now revealed,
Through proofs and queries, timestamps sealed,
From gRPC down to WASM's gleam—
Document versions fulfill the dream! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(drive): add document history retrieval' directly describes the main change across all modified files: a comprehensive feature to add document history retrieval capabilities to the Drive module with supporting gRPC, SDK, and verification infrastructure.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/document-history-retrieval

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 28.07018% with 41 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.16%. Comparing base (7b48e43) to head (b5a9d0b).
⚠️ Report is 7 commits behind head on v3.1-dev.

Files with missing lines Patch % Lines
packages/rs-drive-proof-verifier/src/proof.rs 26.78% 41 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3725      +/-   ##
============================================
- Coverage     87.17%   87.16%   -0.02%     
============================================
  Files          2601     2600       -1     
  Lines        318160   318021     -139     
============================================
- Hits         277370   277211     -159     
- Misses        40790    40810      +20     
Components Coverage Δ
dpp 87.67% <ø> (-0.02%) ⬇️
drive 85.95% <100.00%> (ø)
drive-abci 89.68% <ø> (-0.01%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.17% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.16% <26.78%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/rs-platform-version/src/version/drive_versions/drive_document_method_versions/mod.rs (1)

25-27: ⚡ Quick win

Add freeze assertions for the new historical query method slots.

These fields become part of historical method tables too; adding explicit freeze checks (like the existing primary_key_tree_type guard) will prevent accidental version bumps in already-shipped protocol tables.

Proposed test additions
 #[cfg(test)]
 mod historical_method_table_freeze {
@@
     #[test]
     fn v3_primary_key_tree_type_selects_v1_dispatch() {
         assert_eq!(
             DRIVE_DOCUMENT_METHOD_VERSIONS_V3.primary_key_tree_type, 1,
@@
         );
     }
+
+    #[test]
+    fn v2_document_history_query_slots_are_frozen_at_v0_dispatch() {
+        assert_eq!(DRIVE_DOCUMENT_METHOD_VERSIONS_V2.query.fetch_document_history_query, 0);
+        assert_eq!(DRIVE_DOCUMENT_METHOD_VERSIONS_V2.query.fetch_document_history, 0);
+        assert_eq!(DRIVE_DOCUMENT_METHOD_VERSIONS_V2.query.prove_document_history, 0);
+    }
+
+    #[test]
+    fn v3_document_history_query_slots_are_frozen_at_v0_dispatch() {
+        assert_eq!(DRIVE_DOCUMENT_METHOD_VERSIONS_V3.query.fetch_document_history_query, 0);
+        assert_eq!(DRIVE_DOCUMENT_METHOD_VERSIONS_V3.query.fetch_document_history, 0);
+        assert_eq!(DRIVE_DOCUMENT_METHOD_VERSIONS_V3.query.prove_document_history, 0);
+    }
 }
🤖 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-platform-version/src/version/drive_versions/drive_document_method_versions/mod.rs`
around lines 25 - 27, Add freeze assertions for the new historical method slots
so they cannot be changed after shipping: in the same place where
primary_key_tree_type is guarded, add checks that fetch_document_history_query,
fetch_document_history, and prove_document_history are frozen (or assert their
versions/flags) to prevent accidental bumps in historical method tables; mirror
the exact pattern used for primary_key_tree_type to locate and implement these
guards inside the drive_document_method_versions module.
🤖 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-drive/src/verify/document/verify_document_history/v0/mod.rs`:
- Around line 17-27: The current verify_document_history_v0 decodes every proved
history entry using a single DocumentTypeRef which breaks when the contract
schema changed; update verify_document_history_v0 so that for each history entry
you resolve the DocumentTypeRef that was active at that entry's timestamp (i.e.
lookup the contract revision for the entry's revision/timestamp and use that
revision's document type) before decoding, or alternatively detect if the
requested range spans multiple contract revisions and return a clear error
rejecting cross-revision history requests; make this change where entries are
iterated/decoded (and similarly for the logic referenced around lines 62-69) so
each Document is decoded against the correct historical schema.

---

Nitpick comments:
In
`@packages/rs-platform-version/src/version/drive_versions/drive_document_method_versions/mod.rs`:
- Around line 25-27: Add freeze assertions for the new historical method slots
so they cannot be changed after shipping: in the same place where
primary_key_tree_type is guarded, add checks that fetch_document_history_query,
fetch_document_history, and prove_document_history are frozen (or assert their
versions/flags) to prevent accidental bumps in historical method tables; mirror
the exact pattern used for primary_key_tree_type to locate and implement these
guards inside the drive_document_method_versions module.
🪄 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: 5743c558-0198-4f06-ab5c-4d3a5b2526c6

📥 Commits

Reviewing files that changed from the base of the PR and between f741df2 and b5a9d0b.

📒 Files selected for processing (41)
  • packages/dapi-grpc/build.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/js-evo-sdk/src/documents/facade.ts
  • packages/js-evo-sdk/tests/unit/facades/documents.spec.ts
  • packages/rs-dapi-client/src/transport/grpc.rs
  • packages/rs-drive-abci/src/query/document_history/mod.rs
  • packages/rs-drive-abci/src/query/document_history/v0/mod.rs
  • packages/rs-drive-abci/src/query/mod.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-drive-proof-verifier/src/proof.rs
  • packages/rs-drive-proof-verifier/src/types.rs
  • packages/rs-drive/src/drive/document/get_fetch/fetch_document_history/mod.rs
  • packages/rs-drive/src/drive/document/get_fetch/fetch_document_history/v0/mod.rs
  • packages/rs-drive/src/drive/document/get_fetch/mod.rs
  • packages/rs-drive/src/drive/document/mod.rs
  • packages/rs-drive/src/drive/document/prove/mod.rs
  • packages/rs-drive/src/drive/document/prove/prove_document_history/mod.rs
  • packages/rs-drive/src/drive/document/prove/prove_document_history/v0/mod.rs
  • packages/rs-drive/src/drive/document/query/fetch_document_history_query/mod.rs
  • packages/rs-drive/src/drive/document/query/fetch_document_history_query/v0/mod.rs
  • packages/rs-drive/src/drive/document/query/mod.rs
  • packages/rs-drive/src/error/drive.rs
  • packages/rs-drive/src/verify/document/mod.rs
  • packages/rs-drive/src/verify/document/verify_document_history/mod.rs
  • packages/rs-drive/src/verify/document/verify_document_history/v0/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_document_method_versions/mod.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_document_method_versions/v1.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_document_method_versions/v2.rs
  • packages/rs-platform-version/src/version/drive_versions/drive_document_method_versions/v3.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/mocks/v2_test.rs
  • packages/rs-sdk/src/mock/sdk.rs
  • packages/rs-sdk/src/platform.rs
  • packages/rs-sdk/src/platform/documents/document_history_query.rs
  • packages/rs-sdk/src/platform/documents/mod.rs
  • packages/rs-sdk/src/platform/fetch.rs
  • packages/rs-sdk/src/platform/query.rs
  • packages/wasm-sdk/src/queries/document.rs

Comment on lines +17 to +27
pub(super) fn verify_document_history_v0(
proof: &[u8],
contract_id: [u8; 32],
document_type_name: &str,
document_type: DocumentTypeRef,
document_id: [u8; 32],
start_at_ms: u64,
limit: Option<u16>,
offset: Option<u16>,
platform_version: &PlatformVersion,
) -> Result<(RootHash, Option<BTreeMap<u64, Document>>), Error> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Resolve the document type per historical revision.

This implementation decodes every proved history entry with one DocumentTypeRef. That only holds if the contract schema never changed. Once a data contract update modifies this document type, older revisions in the same history range will be verified against the latest schema and can fail to decode or be interpreted incorrectly. Please either resolve the contract revision that was active for each timestamp, or explicitly reject history ranges that cross contract revisions until that lookup is wired in.

Also applies to: 62-69

🤖 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-drive/src/verify/document/verify_document_history/v0/mod.rs`
around lines 17 - 27, The current verify_document_history_v0 decodes every
proved history entry using a single DocumentTypeRef which breaks when the
contract schema changed; update verify_document_history_v0 so that for each
history entry you resolve the DocumentTypeRef that was active at that entry's
timestamp (i.e. lookup the contract revision for the entry's revision/timestamp
and use that revision's document type) before decoding, or alternatively detect
if the requested range spans multiple contract revisions and return a clear
error rejecting cross-revision history requests; make this change where entries
are iterated/decoded (and similarly for the logic referenced around lines 62-69)
so each Document is decoded against the correct historical schema.

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

The document-history plumbing is mostly coherent, but three user-visible issues remain in the shipped surface. One is blocking: the protobuf service added getDocumentHistory, but the checked-in @dashevo/dapi-grpc generated clients were not regenerated, so published consumers of that package cannot call the new RPC. The other two issues are pagination-semantics regressions: empty history pages are treated as missing resources in the non-proof path and collapsed to None in proof verification.

Note: Inline posting through review_poster.py failed with GitHub HTTP 422, so I posted the same verified findings as a top-level review body.

Reviewed commit: b5a9d0b

🔴 1 blocking | 🟡 2 suggestion(s)

Verified findings

blocking: The new RPC is declared in the proto, but the checked-in generated DAPI clients do not expose it

packages/dapi-grpc/protos/platform/v0/platform.proto (line 38)

@dashevo/dapi-grpc ships generated client artifacts from packages/dapi-grpc/clients and re-exports them from node.js and browser.js. After adding rpc getDocumentHistory(...), the repository still contains no generated getDocumentHistory / GetDocumentHistory* symbols under packages/dapi-grpc/clients/platform/v0, so workspace and published-package consumers that rely on those checked-in clients cannot construct or invoke the new method. The Rust path works because it regenerates from the proto during build, but the package that advertises generated clients is stale in the committed source.

suggestion: Empty document-history pages are converted into `NotFound` in the non-proof path

packages/rs-drive-abci/src/query/document_history/v0/mod.rs (line 120)

This branch turns any empty result set into QueryError::NotFound, which breaks normal pagination semantics. Requests such as offset past the last revision or start_at_ms after the newest revision are valid queries against an existing document history and should return an empty page, not a transport error. As written, raw DAPI callers using prove = false cannot paginate until exhaustion without treating the final page as failure, and they cannot distinguish an empty page from an actually invalid document ID.

suggestion: Proof verification collapses an empty history page into `None`

packages/rs-drive/src/verify/document/verify_document_history/v0/mod.rs (line 83)

verify_document_history_v0() returns None whenever the verified map is empty. That loses information for paginated history queries, because a valid empty page and a genuinely absent history become indistinguishable after proof verification. The analogous contract-history verifier returns Some(empty_map), which preserves collection semantics. Returning Some(documents) here keeps the proof-decoded result lossless and aligns the verifier with the collection behavior expected by limit/offset queries.

Ok((root_hash, Some(documents)))
🤖 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.

- [BLOCKING] In `packages/dapi-grpc/protos/platform/v0/platform.proto`:38-39: The new RPC is declared in the proto, but the checked-in generated DAPI clients do not expose it
  `@dashevo/dapi-grpc` ships generated client artifacts from `packages/dapi-grpc/clients` and re-exports them from `node.js` and `browser.js`. After adding `rpc getDocumentHistory(...)`, the repository still contains no generated `getDocumentHistory` / `GetDocumentHistory*` symbols under `packages/dapi-grpc/clients/platform/v0`, so workspace and published-package consumers that rely on those checked-in clients cannot construct or invoke the new method. The Rust path works because it regenerates from the proto during build, but the package that advertises generated clients is stale in the committed source.
- [SUGGESTION] In `packages/rs-drive-abci/src/query/document_history/v0/mod.rs`:120-123: Empty document-history pages are converted into `NotFound` in the non-proof path
  This branch turns any empty result set into `QueryError::NotFound`, which breaks normal pagination semantics. Requests such as `offset` past the last revision or `start_at_ms` after the newest revision are valid queries against an existing document history and should return an empty page, not a transport error. As written, raw DAPI callers using `prove = false` cannot paginate until exhaustion without treating the final page as failure, and they cannot distinguish an empty page from an actually invalid document ID.
- [SUGGESTION] In `packages/rs-drive/src/verify/document/verify_document_history/v0/mod.rs`:83-89: Proof verification collapses an empty history page into `None`
  `verify_document_history_v0()` returns `None` whenever the verified map is empty. That loses information for paginated history queries, because a valid empty page and a genuinely absent history become indistinguishable after proof verification. The analogous contract-history verifier returns `Some(empty_map)`, which preserves collection semantics. Returning `Some(documents)` here keeps the proof-decoded result lossless and aligns the verifier with the collection behavior expected by limit/offset queries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants