From 8321017b889c268fad4f8cfe2ba0659644dcd38c Mon Sep 17 00:00:00 2001 From: Lil Claw Date: Wed, 1 Jul 2026 02:21:03 -0500 Subject: [PATCH 1/3] build: update rust-dashcore to v0.44.0 (#3973) Co-authored-by: PastaClaw Co-authored-by: Claude Opus 4.7 (1M context) --- Cargo.lock | 70 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 16 ++++++------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8de05bacd9..1ca6768db2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1206,7 +1206,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1636,8 +1636,8 @@ dependencies = [ [[package]] name = "dash-network" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "bincode", "bincode_derive", @@ -1647,8 +1647,8 @@ dependencies = [ [[package]] name = "dash-network-seeds" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "dash-network", ] @@ -1724,8 +1724,8 @@ dependencies = [ [[package]] name = "dash-spv" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "async-trait", "chrono", @@ -1753,8 +1753,8 @@ dependencies = [ [[package]] name = "dashcore" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "anyhow", "base64-compat", @@ -1779,13 +1779,13 @@ dependencies = [ [[package]] name = "dashcore-private" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" [[package]] name = "dashcore-rpc" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "dashcore-rpc-json", "hex", @@ -1797,8 +1797,8 @@ dependencies = [ [[package]] name = "dashcore-rpc-json" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "bincode", "dashcore", @@ -1812,8 +1812,8 @@ dependencies = [ [[package]] name = "dashcore_hashes" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "bincode", "dashcore-private", @@ -2428,7 +2428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2489,7 +2489,7 @@ checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2866,8 +2866,8 @@ dependencies = [ [[package]] name = "git-state" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" [[package]] name = "glob" @@ -3803,7 +3803,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4033,8 +4033,8 @@ dependencies = [ [[package]] name = "key-wallet" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "aes", "async-trait", @@ -4062,8 +4062,8 @@ dependencies = [ [[package]] name = "key-wallet-ffi" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "cbindgen 0.29.4", "dash-network", @@ -4078,8 +4078,8 @@ dependencies = [ [[package]] name = "key-wallet-manager" -version = "0.43.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=5c0113e7901551450f6063023eec4be95beeb6b9#5c0113e7901551450f6063023eec4be95beeb6b9" +version = "0.44.0" +source = "git+https://github.com/dashpay/rust-dashcore?rev=991c6ebe24d7ea8ba7d900a052b25be8c5498409#991c6ebe24d7ea8ba7d900a052b25be8c5498409" dependencies = [ "async-trait", "bincode", @@ -4596,7 +4596,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5696,7 +5696,7 @@ dependencies = [ "once_cell", "socket2 0.5.10", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6486,7 +6486,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6499,7 +6499,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6558,7 +6558,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -7418,7 +7418,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -8867,7 +8867,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5d5f2960f1..6d462f6275 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,14 +50,14 @@ members = [ ] [workspace.dependencies] -dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "5c0113e7901551450f6063023eec4be95beeb6b9" } +dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } +dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "991c6ebe24d7ea8ba7d900a052b25be8c5498409" } tokio-metrics = "0.5" From 9a80f985265662666bfcd600f6d04de78f6d694a Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 1 Jul 2026 15:38:12 +0700 Subject: [PATCH 2/3] chore: retarget in-repo branch references from v3.1-dev to v4.0-dev (#3972) Co-authored-by: Claude Opus 4.8 (1M context) --- .claude/skills/pr-description/SKILL.md | 2 +- NIGHTLY_STATUS.md | 6 ++--- README.md | 12 +++++----- book/src/drive/average-index-examples.md | 12 +++++----- book/src/drive/count-index-examples.md | 10 ++++----- .../drive/count-index-group-by-examples.md | 14 ++++++------ book/src/drive/document-count-trees.md | 20 ++++++++--------- book/src/drive/document-sum-trees.md | 4 ++-- book/src/drive/indexes.md | 22 +++++++++---------- book/src/drive/sum-index-examples.md | 8 +++---- .../PlatformWalletManagerShieldedSync.swift | 2 +- 11 files changed, 56 insertions(+), 56 deletions(-) diff --git a/.claude/skills/pr-description/SKILL.md b/.claude/skills/pr-description/SKILL.md index ec57684287..bd7a072f40 100644 --- a/.claude/skills/pr-description/SKILL.md +++ b/.claude/skills/pr-description/SKILL.md @@ -13,7 +13,7 @@ Generate a pull request title and description for the current branch using the p 1. Determine the base branch: - Use the argument if provided - Otherwise, auto-detect: `git remote set-head origin --auto >/dev/null 2>&1 && git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/||'` - - Fall back to `v3.1-dev` if the command above fails + - Fall back to `v4.0-dev` if the command above fails 2. Gather context by running these git commands: - `git log --oneline $(git merge-base HEAD )..HEAD` — all commits on this branch diff --git a/NIGHTLY_STATUS.md b/NIGHTLY_STATUS.md index 43efc08683..52b29bd2b3 100644 --- a/NIGHTLY_STATUS.md +++ b/NIGHTLY_STATUS.md @@ -2,9 +2,9 @@ [![Nightly Tests](https://github.com/dashpay/platform/actions/workflows/tests.yml/badge.svg?event=schedule)](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule) -> **Note:** This page is manually maintained. For live results, check the [latest nightly run](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule+branch%3Av3.1-dev) directly. +> **Note:** This page is manually maintained. For live results, check the [latest nightly run](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule+branch%3Av4.0-dev) directly. -Nightly tests run every day at **23:00 UTC** on the `v3.1-dev` branch via the [Tests workflow](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule). They exercise the full CI pipeline including Docker image builds, E2E tests, and the platform test suite. +Nightly tests run every day at **23:00 UTC** on the `v4.0-dev` branch via the [Tests workflow](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule). They exercise the full CI pipeline including Docker image builds, E2E tests, and the platform test suite. ## Nightly Jobs @@ -52,7 +52,7 @@ The functional tests have been intermittently failing for months. This is a know ## Links - [All nightly runs](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule) -- [Latest nightly run](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule+branch%3Av3.1-dev) +- [Latest nightly run](https://github.com/dashpay/platform/actions/workflows/tests.yml?query=event%3Aschedule+branch%3Av4.0-dev) - [Long-running Rust nightly](https://github.com/dashpay/platform/actions/workflows/tests-rs-nightly-long-running.yml) - [Security audits (Rust)](https://github.com/dashpay/platform/actions/workflows/security-audit-rust.yml) - [Security audits (JS - npm)](https://github.com/dashpay/platform/actions/workflows/security-audit-js-npm.yml) diff --git a/README.md b/README.md index 0335eceed4..6663cf2bba 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@

CI - Nightly Tests - codecov + Nightly Tests + codecov commit activity last commit General Chat @@ -24,10 +24,10 @@ | Crate | Lines | Coverage | |-------|------:|----------| -| [rs-dpp](./packages/rs-dpp) | 129k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v3.1-dev/graph/badge.svg?component=dpp)](https://codecov.io/gh/dashpay/platform/component/dpp) | -| [rs-drive](./packages/rs-drive) | 171k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v3.1-dev/graph/badge.svg?component=drive)](https://codecov.io/gh/dashpay/platform/component/drive) | -| [rs-drive-abci](./packages/rs-drive-abci) | 125k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v3.1-dev/graph/badge.svg?component=drive-abci)](https://codecov.io/gh/dashpay/platform/component/drive-abci) | -| [rs-sdk](./packages/rs-sdk) | 23k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v3.1-dev/graph/badge.svg?component=sdk)](https://codecov.io/gh/dashpay/platform/component/sdk) | +| [rs-dpp](./packages/rs-dpp) | 129k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v4.0-dev/graph/badge.svg?component=dpp)](https://codecov.io/gh/dashpay/platform/component/dpp) | +| [rs-drive](./packages/rs-drive) | 171k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v4.0-dev/graph/badge.svg?component=drive)](https://codecov.io/gh/dashpay/platform/component/drive) | +| [rs-drive-abci](./packages/rs-drive-abci) | 125k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v4.0-dev/graph/badge.svg?component=drive-abci)](https://codecov.io/gh/dashpay/platform/component/drive-abci) | +| [rs-sdk](./packages/rs-sdk) | 23k | [![codecov](https://codecov.io/gh/dashpay/platform/branch/v4.0-dev/graph/badge.svg?component=sdk)](https://codecov.io/gh/dashpay/platform/component/sdk) | diff --git a/book/src/drive/average-index-examples.md b/book/src/drive/average-index-examples.md index 997ab58b8a..c707b9ddb8 100644 --- a/book/src/drive/average-index-examples.md +++ b/book/src/drive/average-index-examples.md @@ -1,10 +1,10 @@ # Average Index Examples -This chapter walks through a representative contract and shows how **average queries** work on Drive. Every example uses the same `grade` document type on the **grades contract** at [`packages/rs-drive/tests/supporting_files/contract/grades/grades-contract.json`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/tests/supporting_files/contract/grades/grades-contract.json). +This chapter walks through a representative contract and shows how **average queries** work on Drive. Every example uses the same `grade` document type on the **grades contract** at [`packages/rs-drive/tests/supporting_files/contract/grades/grades-contract.json`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/tests/supporting_files/contract/grades/grades-contract.json). The chapter assumes you've read [Document Count Trees](./document-count-trees.md) and [Document Sum Trees](./document-sum-trees.md) — averages are built directly on top of both, so understanding count + sum trees individually is the prerequisite. Here we take that machinery as given and look at the queries that need *both*. -> **Status:** the [`document_average_worst_case`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_average_worst_case.rs) bench lands the reproducible numbers below — same convention as the [Count](./count-index-examples.md) and [Sum](./sum-index-examples.md) chapters. All proof sizes are measured against a 31 620-grade fixture; verified `(count, sum)` values are the actual numbers the bench's matrix reports. The full surface — primary-key global average, point lookups, range aggregates, and both carrier variants — is wired through to grovedb PR #670's verifiers end-to-end. +> **Status:** the [`document_average_worst_case`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_average_worst_case.rs) bench lands the reproducible numbers below — same convention as the [Count](./count-index-examples.md) and [Sum](./sum-index-examples.md) chapters. All proof sizes are measured against a 31 620-grade fixture; verified `(count, sum)` values are the actual numbers the bench's matrix reports. The full surface — primary-key global average, point lookups, range aggregates, and both carrier variants — is wired through to grovedb PR #670's verifiers end-to-end. ## Why Averages Need a New Primitive @@ -70,11 +70,11 @@ Five things to internalize before reading the queries: 2. **`byClass` / `byStudent` / `bySemester` are `countable: countable` + `summable: "score"`** (no range flags). Each per-key value-tree (one per class / student / semester) is a **`CountSumTree`** carrying both metrics at one merk lookup — point-lookup averages get the same shortcut count proofs and sum proofs do. 3. **`byClassSemester` and `byStudentSemester` set both range flags** (`rangeCountable: true` AND `rangeSummable: true`). The `semester` continuation under each (class | student) value-tree is a **`ProvableCountProvableSumTree`** (PCPS), the structurally-richest tree variant — every internal merk node carries both a per-node count *and* a per-node sum. This is what `AggregateCountAndSumOnRange` walks for "average for class X in semester range [a..b]" style queries. 4. **Every `summable` index here is also `countable`.** There's no `summable`-only index in this contract — averages need both axes, so a sum-only index would be unreachable from the average surface. (Pure-sum surfaces are covered by the [tip-jar contract](./sum-index-examples.md) in the previous chapter; the grades contract is deliberately the dual-axis counterpart.) -5. **`countableAllowingOffset` on the PCPS indexes** — `rangeCountable: true` requires the count tier to be `countable` or `countableAllowingOffset` (per the rule documented in [`Index::range_countable`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-dpp/src/data_contract/document_type/index/mod.rs)). The offset-allowing tier upgrades the property-name tree to a `ProvableCountTree` at minimum; combined with `summable: "score"` and `rangeSummable: true` the dispatcher resolves it to PCPS. +5. **`countableAllowingOffset` on the PCPS indexes** — `rangeCountable: true` requires the count tier to be `countable` or `countableAllowingOffset` (per the rule documented in [`Index::range_countable`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-dpp/src/data_contract/document_type/index/mod.rs)). The offset-allowing tier upgrades the property-name tree to a `ProvableCountTree` at minimum; combined with `summable: "score"` and `rangeSummable: true` the dispatcher resolves it to PCPS. The bench populates **50 000 grades** under a deterministic, realistic-data-shaped schedule: 500 students × 10 classes × 10 semesters = 50 000 grade documents. The score model layers three deterministic axes: -- **Per-class baseline + spread** (see [`class_profile` in the bench](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_average_worst_case.rs)) — hard classes get low means and wide spreads; easy classes cluster near 85–90 with narrow spreads. The 10 classes have semantic names matching the chapter's references: +- **Per-class baseline + spread** (see [`class_profile` in the bench](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_average_worst_case.rs)) — hard classes get low means and wide spreads; easy classes cluster near 85–90 with narrow spreads. The 10 classes have semantic names matching the chapter's references: | Class | Baseline mean | Spread | Profile | |---|---|---|---| @@ -94,7 +94,7 @@ The bench populates **50 000 grades** under a deterministic, realistic-data-shap A skill score is *amplified by class spread* — `skill × spread / 8` — so a +10-skill student in PHYS101 (spread=12) gains +15 over baseline, while the same student in ARTS101 (spread=4) only gains +5. This produces the realistic spread real transcripts exhibit: a strong student stands out more in hard classes, struggling students fall further behind in hard classes, easy classes flatten the curve. -**Realistic enrollment.** Not every student takes every class — that's not how transcripts work. The bench walks all 500 × 10 × 10 = 50 000 possible `(student, class, semester)` triples but only emits a grade when [`is_enrolled`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_average_worst_case.rs) returns true, using a deterministic per-class popularity table: +**Realistic enrollment.** Not every student takes every class — that's not how transcripts work. The bench walks all 500 × 10 × 10 = 50 000 possible `(student, class, semester)` triples but only emits a grade when [`is_enrolled`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_average_worst_case.rs) returns true, using a deterministic per-class popularity table: | Class | Popularity | Profile | |---|---|---| @@ -1699,7 +1699,7 @@ The split closely parallels the count and sum chapters — point lookups for Q1 ## What's Next -The chapter is grounded in the [`document_average_worst_case`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_average_worst_case.rs) bench's measured numbers — Q1–Q7 verify cleanly end-to-end against the shared root hash `8b15f732…ffc7`. +The chapter is grounded in the [`document_average_worst_case`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_average_worst_case.rs) bench's measured numbers — Q1–Q7 verify cleanly end-to-end against the shared root hash `8b15f732…ffc7`. A natural expansion follow-up (out of scope here): a worked example of "exact-precision" averages — for callers that need fractional averages (e.g. `avg = 50.7142857…` rather than `50.99`), the protocol-level approach is to return `(count, sum)` and let the client compute in its preferred numeric format (the chapter notes this in [Numerical Considerations](#numerical-considerations) above; a future expansion could walk through the fixed-point vs. floating-point trade-offs). diff --git a/book/src/drive/count-index-examples.md b/book/src/drive/count-index-examples.md index 2cf1de6145..c1d086638e 100644 --- a/book/src/drive/count-index-examples.md +++ b/book/src/drive/count-index-examples.md @@ -1,6 +1,6 @@ # Count Index Examples -This chapter walks through a representative contract and shows what a count-query proof actually proves — both the path query the prover signs and the verified element the verifier extracts. Every example uses the same `widget` contract (the same one the count-query bench at [`packages/rs-drive/benches/document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_count_worst_case.rs) populates) so the proof bytes, verified elements, and diagrams can all be cross-referenced against the same data. +This chapter walks through a representative contract and shows what a count-query proof actually proves — both the path query the prover signs and the verified element the verifier extracts. Every example uses the same `widget` contract (the same one the count-query bench at [`packages/rs-drive/benches/document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_count_worst_case.rs) populates) so the proof bytes, verified elements, and diagrams can all be cross-referenced against the same data. The chapter assumes you've read [Document Count Trees](./document-count-trees.md) — that chapter explains the three tree variants (`NormalTree` / `CountTree` / `ProvableCountTree`), what `Element::NonCounted` does, and how the schema's `documentsCountable` / `rangeCountable` flags select between them. Here we take that machinery as given and trace what each query *sees*. @@ -44,7 +44,7 @@ The widget document type carries three properties (`brand`, `color`, `serial`), Three things to notice: 1. **`documentsCountable: true`** at the document-type level upgrades the doctype's primary-key subtree (at `widget/[0]`) from `NormalTree` to `CountTree`. The unfiltered total count is one read against this element's `count_value`. -2. **`byBrand` is `countable: "countable"` only.** It doesn't opt into `rangeCountable`, so `brand > X` range counts aren't supported. But **every countable terminator's value tree is stored as a `CountTree`** regardless of `rangeCountable` (see [`add_indices_for_index_level_for_contract_operations/v0/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs)), so point-lookup count proofs (e.g. `brand == "X"` or `brand IN [...]`) get the same compact value-tree-direct shape on byBrand that they do on rangeCountable indexes. `rangeCountable` is strictly an opt-in for `AggregateCountOnRange` support — orthogonal to proof-size shape. +2. **`byBrand` is `countable: "countable"` only.** It doesn't opt into `rangeCountable`, so `brand > X` range counts aren't supported. But **every countable terminator's value tree is stored as a `CountTree`** regardless of `rangeCountable` (see [`add_indices_for_index_level_for_contract_operations/v0/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs)), so point-lookup count proofs (e.g. `brand == "X"` or `brand IN [...]`) get the same compact value-tree-direct shape on byBrand that they do on rangeCountable indexes. `rangeCountable` is strictly an opt-in for `AggregateCountOnRange` support — orthogonal to proof-size shape. 3. **`byColor` and `byBrandColor` are `rangeCountable: true`.** Their property-name subtrees (e.g. `widget/color`) are stored as `ProvableCountTree` rather than `NormalTree`, which is what `AggregateCountOnRange` walks for `color > floor` style queries. The bench populates 100 000 documents under a deterministic schedule — `row → (brand_(row % 100), color_(row / 100), serial=row)`. That gives exactly 1 000 docs per brand, exactly 100 docs per color, and exactly 1 doc per `(brand, color)` pair. Those numbers show up in every verified count below. @@ -86,7 +86,7 @@ flowchart TB Three layout facts to internalize before reading the queries: -- **`brand_050` is a `CountTree` with `count_value = 1000`.** That's true *because* `byBrand` is countable; the rule applies uniformly to every countability tier (see [`add_indices_for_index_level_for_contract_operations/v0/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs)). The `color` continuation that branches off this value tree is `NonCounted`-wrapped so the parent's count equals exactly the 1 000 refs in `[0]`. +- **`brand_050` is a `CountTree` with `count_value = 1000`.** That's true *because* `byBrand` is countable; the rule applies uniformly to every countability tier (see [`add_indices_for_index_level_for_contract_operations/v0/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs)). The `color` continuation that branches off this value tree is `NonCounted`-wrapped so the parent's count equals exactly the 1 000 refs in `[0]`. - **`widget/color` is a `ProvableCountTree`**, not a regular `NormalTree`. The yellow class above marks that — each internal merk node carries its subtree's count, which is what makes `AggregateCountOnRange` a single-pass primitive. - **`color_00000500` is a `CountTree` with `count_value = 100`** under either parent. The same element layout would result from a query against `byColor` or against `byBrandColor`'s second level; the path that gets there differs, but the destination is structurally the same. @@ -99,7 +99,7 @@ Every example below has four sections: 3. **Proof display** — the proof bytes, decoded via `bincode` into the structured `GroveDBProof` AST and rendered through its `Display` impl. This is the same view [dash-evo-tool's Proof Log screen](https://github.com/dashpay/dash-evo-tool/blob/master/src/ui/tools/proof_log_screen.rs) shows when its display mode is set to "JSON" — each layer is a separate `LayerProof` carrying its merk-tree operations (`Push` / `Parent` / `Child` over `Hash` / `KVValueHash` / `KVHash`) plus a `lower_layers` map naming the children to descend into. Wrapped in a collapsible block per example because the merk path through 4-5 grovedb layers makes for long output. 4. **Diagram** — the path the proof walks through the layout. Blue arrows trace the descent; the cyan node is the verified element; faded gray nodes show context. -All proof-size numbers come from running the bench against a 100 000-row fixture; see [`document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_count_worst_case.rs)'s `report_proof_sizes` / `display_proofs` / `report_group_by_matrix` helpers. The proof bytes are reproducible — run the bench, grep `[proof]` from stderr, and you'll get the same hashes shown here. +All proof-size numbers come from running the bench against a 100 000-row fixture; see [`document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_count_worst_case.rs)'s `report_proof_sizes` / `display_proofs` / `report_group_by_matrix` helpers. The proof bytes are reproducible — run the bench, grep `[proof]` from stderr, and you'll get the same hashes shown here. ## Queries in this Chapter @@ -1863,4 +1863,4 @@ Four takeaways: - **Queries 7 and 8 use a fundamentally different verifier** (`verify_aggregate_count_query` vs `verify_query`). Queries 1–6 return an element list and read `count_value_or_default` per branch; Queries 7 and 8 return a pre-summed `u64`. Query 8 is just Query 7 one grove layer deeper — same primitive, applied to byBrandColor's terminator rather than byColor's. - **Query 8 is the most expensive.** It pays for both the compound descent (Query 4's 4-extra-layer cost) *and* the range-aggregate boundary (Query 7's primitive). The verified count is far smaller than Query 7 (499 vs 49 900), but the proof bytes are 28 % larger because the merk-tree boundary at L8 has roughly the same shape regardless of how many keys the cut spans. -The path-query builder these examples decode lives at [`packages/rs-drive/src/query/drive_document_count_query/path_query.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/path_query.rs); the verifier mirror sits in [`packages/rs-drive/src/verify/document_count/`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/verify/document_count/). Both the prover and the verifier reconstruct the exact same `PathQuery` via the shared builder — touching one without the other is a Merkle-root mismatch waiting to happen, and the byte-identical contract is what makes the proof bytes here reproducible against the bench fixture. +The path-query builder these examples decode lives at [`packages/rs-drive/src/query/drive_document_count_query/path_query.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/path_query.rs); the verifier mirror sits in [`packages/rs-drive/src/verify/document_count/`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/verify/document_count/). Both the prover and the verifier reconstruct the exact same `PathQuery` via the shared builder — touching one without the other is a Merkle-root mismatch waiting to happen, and the byte-identical contract is what makes the proof bytes here reproducible against the bench fixture. diff --git a/book/src/drive/count-index-group-by-examples.md b/book/src/drive/count-index-group-by-examples.md index 29d16c8057..4d82077579 100644 --- a/book/src/drive/count-index-group-by-examples.md +++ b/book/src/drive/count-index-group-by-examples.md @@ -1,6 +1,6 @@ # Count Index Group By Examples -This chapter is the `GROUP BY` companion to [Count Index Examples](./count-index-examples.md). It uses the same `widget` contract, the same 100 000-row fixture, and the same bench at [`packages/rs-drive/benches/document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_count_worst_case.rs). Read chapter 29 first — most of the mechanics (CountTree variants, the merk-proof reconstruction algorithm, `node_hash_with_count` and friends) carry over unchanged. +This chapter is the `GROUP BY` companion to [Count Index Examples](./count-index-examples.md). It uses the same `widget` contract, the same 100 000-row fixture, and the same bench at [`packages/rs-drive/benches/document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_count_worst_case.rs). Read chapter 29 first — most of the mechanics (CountTree variants, the merk-proof reconstruction algorithm, `node_hash_with_count` and friends) carry over unchanged. What's different here: @@ -35,7 +35,7 @@ Range queries are different. `AggregateCountOnRange` (chapter 29's Q7) walks the ## Queries in this Chapter -All proof-size and behaviour numbers below come from the same bench helper (`report_group_by_matrix`) as chapter 29's. The dispatcher's group_by surface validation lives in [`validate_count_query_groupby_against_index`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/validate.rs); the per-mode path-query builders sit in [`packages/rs-drive/src/query/drive_document_count_query/path_query.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/path_query.rs)'s `group_by_*` family. +All proof-size and behaviour numbers below come from the same bench helper (`report_group_by_matrix`) as chapter 29's. The dispatcher's group_by surface validation lives in [`validate_count_query_groupby_against_index`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/validate.rs); the per-mode path-query builders sit in [`packages/rs-drive/src/query/drive_document_count_query/path_query.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/path_query.rs)'s `group_by_*` family. | # | Query | Filter + group_by | Complexity | Avg time | Proof size | Verified shape | Notes | |---|-------|-------------------|------------|----------|------------|----------------|-------| @@ -194,7 +194,7 @@ Entries([ ]) ``` -This is the load-bearing behaviour to know about: grovedb's `verify_query` *without* `absence_proofs_for_non_existing_searched_keys: true` drops absent-Key branches from the elements stream. The drive-side verifier ([`verify_point_lookup_count_proof_v0`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/verify/document_count/verify_point_lookup_count_proof/v0/mod.rs)) uses the default (off) and so emits one entry per **present** In value, not one per **requested** In value. Test coverage: [`test_point_lookup_proof_omits_absent_in_branches_from_entries`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/tests.rs). +This is the load-bearing behaviour to know about: grovedb's `verify_query` *without* `absence_proofs_for_non_existing_searched_keys: true` drops absent-Key branches from the elements stream. The drive-side verifier ([`verify_point_lookup_count_proof_v0`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/verify/document_count/verify_point_lookup_count_proof/v0/mod.rs)) uses the default (off) and so emits one entry per **present** In value, not one per **requested** In value. Test coverage: [`test_point_lookup_proof_omits_absent_in_branches_from_entries`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/tests.rs). **Caller implication.** Callers MUST NOT assume `entries.len() == |In|`. To check whether a specific In value matched, demux entries by serialized key (the same `serialize_value_for_key(field, value)` the path-query builder uses for outer Keys) — see the test for the canonical pattern. A `0`-count vs absent-key distinction would require passing `absence_proofs_for_non_existing_searched_keys: true` end-to-end, which the platform doesn't expose today. @@ -840,7 +840,7 @@ Entries(100 groups, sum = 10 000) The 100 groups are color_00000501 through color_00000600 (the first 100 in-range colors in lex-asc order, capped by the limit). Each carries `count_value_or_default = 100` since the fixture's deterministic schedule gives each color exactly 100 documents. -Wait — but [Q7](./count-index-examples.md#query-7--range-query-aggregatecountonrange) said there are 499 distinct in-range colors and `sum = 49 900` over the same `color > "color_00000500"` predicate. So why does G4 see only 100 groups summing to 10 000? Because `GroupByRange`'s `distinct_count_path_query` applies the 100-entry response cap (`Some(limit)` in [`execute_distinct_count_with_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/execute_range_count.rs)). Without that cap the proof would scale linearly with the full in-range distinct count (~5.5 KB for the full 499 colors at ~110 B per resolved CountTree branch). The cap is a response-size safety control — the verifier ceases the walk once it has 100 entries. +Wait — but [Q7](./count-index-examples.md#query-7--range-query-aggregatecountonrange) said there are 499 distinct in-range colors and `sum = 49 900` over the same `color > "color_00000500"` predicate. So why does G4 see only 100 groups summing to 10 000? Because `GroupByRange`'s `distinct_count_path_query` applies the 100-entry response cap (`Some(limit)` in [`execute_distinct_count_with_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/execute_range_count.rs)). Without that cap the proof would scale linearly with the full in-range distinct count (~5.5 KB for the full 499 colors at ~110 B per resolved CountTree branch). The cap is a response-size safety control — the verifier ceases the walk once it has 100 entries. **Proof size:** 10 992 B — ~5.3 × [Q7](./count-index-examples.md#query-7--range-query-aggregatecountonrange). The structural reason: @@ -1538,7 +1538,7 @@ SizedQuery::limit: 10 // platform defa outer Query.left_to_right: false // from order_by [(brand, desc)] ``` -**Same-field range merging.** The caller's wire shape carries *four* range clauses (`brand >`, `brand <`, `color >`, `color <`). The dispatcher merges each same-field pair into a single `BetweenExcludeBounds` clause via [`merge_same_field_range_pairs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs) before mode detection runs. After merging, the structure is identical to G8's two-range shape; mode detection routes to `RangeAggregateCarrierProof` for the same reasons. +**Same-field range merging.** The caller's wire shape carries *four* range clauses (`brand >`, `brand <`, `color >`, `color <`). The dispatcher merges each same-field pair into a single `BetweenExcludeBounds` clause via [`merge_same_field_range_pairs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs) before mode detection runs. After merging, the structure is identical to G8's two-range shape; mode detection routes to `RangeAggregateCarrierProof` for the same reasons. **Verified payload** (descending walk — outer keys come out from highest to lowest, capped at `L = 10`): @@ -1684,7 +1684,7 @@ group_by = [brand, color] prove = true ``` -**Outcome:** `Err(QuerySyntaxError::InvalidWhereClauseComponents("count query supports at most one range where-clause; combine two-sided ranges via `between*` instead of separate `>` / `<` clauses, or use `group_by = [outer_range_field]` with `prove = true` for the carrier-aggregate shape with one outer range and one inner ACOR range on a different field"))` — at [`detect_mode`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/mode_detection.rs)'s `range_count > 1` short-circuit, before any index picking or path-query building. +**Outcome:** `Err(QuerySyntaxError::InvalidWhereClauseComponents("count query supports at most one range where-clause; combine two-sided ranges via `between*` instead of separate `>` / `<` clauses, or use `group_by = [outer_range_field]` with `prove = true` for the carrier-aggregate shape with one outer range and one inner ACOR range on a different field"))` — at [`detect_mode`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/mode_detection.rs)'s `range_count > 1` short-circuit, before any index picking or path-query building. **Why.** The two-range carrier shape (`outer_range AND inner_range` on distinct fields) is opened by mode detection **only** when `mode == GroupByRange` *and* `group_by.len() == 1` *and* `prove = true`. G8b violates the first two: with `group_by = [brand, color]` the request maps to `CountMode::GroupByCompound`, which routes to `distinct_count_path_query` — a builder that knows how to walk an `In + range` fan-out but not a `range + range` cartesian product. Two design points: @@ -1721,7 +1721,7 @@ This chapter now mirrors chapter 29's per-query structure: every section above c Two pieces of infrastructure made this possible: -- `query_g1_*` … `query_g6_*` criterion `bench_function` calls in [`document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_count_worst_case.rs) — produce the **Avg time** column in [Queries in this Chapter](#queries-in-this-chapter). +- `query_g1_*` … `query_g6_*` criterion `bench_function` calls in [`document_count_worst_case.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_count_worst_case.rs) — produce the **Avg time** column in [Queries in this Chapter](#queries-in-this-chapter). - `display_group_by_proofs` (a sibling of `display_proofs` in the same bench file) — emits each `group_by` shape's verbatim merk-proof structure via bincode decode + `GroveDBProof::Display`. Tagged with `[gproof]` prefix in stderr so reviewers can grep deterministically. Open follow-ups: diff --git a/book/src/drive/document-count-trees.md b/book/src/drive/document-count-trees.md index e858971ef4..6250753ee5 100644 --- a/book/src/drive/document-count-trees.md +++ b/book/src/drive/document-count-trees.md @@ -60,7 +60,7 @@ A document type opts in via two schema flags: ## How a Document Type Picks Its Tree Variant -Selection lives in [`packages/rs-drive/src/drive/document/primary_key_tree_type.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs): +Selection lives in [`packages/rs-drive/src/drive/document/primary_key_tree_type.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs): ```rust impl DocumentTypePrimaryKeyTreeType for DocumentTypeRef<'_> { @@ -122,9 +122,9 @@ A single unified gRPC endpoint exposes the feature: `GetDocumentsCount`. The res ### No-Prove (Server-Side O(1) or O(log n)) -When `prove=false`, drive-abci calls into `DriveDocumentCountQuery` (in [`packages/rs-drive/src/query/drive_document_count_query/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/mod.rs)). The handler picks a path based on the where clauses: +When `prove=false`, drive-abci calls into `DriveDocumentCountQuery` (in [`packages/rs-drive/src/query/drive_document_count_query/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/mod.rs)). The handler picks a path based on the where clauses: -**Unfiltered total (no where clauses) on a `documentsCountable: true` document type** ([`Drive::read_primary_key_count_tree`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs)): +**Unfiltered total (no where clauses) on a `documentsCountable: true` document type** ([`Drive::read_primary_key_count_tree`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs)): The doctype's primary-key tree at `[contract_doc, contract_id, 1, doctype, 0]` is itself a `CountTree`. One grovedb read gives `count_value` — the total document count. O(1). @@ -153,17 +153,17 @@ When `prove=true`, the proof shape depends on whether the query carries a range - **Aggregate (`return_distinct_counts_in_range = false`, default)**: drive-abci builds a grovedb [`AggregateCountOnRange`](https://docs.rs/grovedb/latest/grovedb/struct.GroveDb.html#method.verify_aggregate_count_query) path query against the property-name `ProvableCountTree`, and `get_proved_path_query` produces an aggregate-count proof. The client verifies via `GroveDb::verify_aggregate_count_query` and recovers `(root_hash, count)` directly — proof size is O(log n) regardless of how many keys match. No documents are ever materialized. -- **Distinct (`return_distinct_counts_in_range = true`)**: drive-abci builds a *regular* range path query (no `AggregateCountOnRange` wrapper) against the same `ProvableCountTree`. Because the leaf is a `ProvableCountTree`, merk emits one `Node::KVCount(key, value, count)` op per matched in-range key, with each `count` cryptographically committed to the merk root via `node_hash_with_count(kv_hash, l_hash, r_hash, count)` — same forge-resistance as the aggregate path's `HashWithCount` collapse. The SDK's [`drive_proof_verifier::verify_distinct_count_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) runs the standard hash-chain check, then walks the proof's op stream to extract the counts as a `BTreeMap, u64>`. Trade-off vs. the aggregate path: proof size is O(distinct values matched) rather than O(log n), because each distinct in-range key emits its own `KVCount` op instead of being collapsed into a boundary subtree. Acceptable for typical histograms (a few dozen distinct values in range); for "give me a single count" use the aggregate path instead. +- **Distinct (`return_distinct_counts_in_range = true`)**: drive-abci builds a *regular* range path query (no `AggregateCountOnRange` wrapper) against the same `ProvableCountTree`. Because the leaf is a `ProvableCountTree`, merk emits one `Node::KVCount(key, value, count)` op per matched in-range key, with each `count` cryptographically committed to the merk root via `node_hash_with_count(kv_hash, l_hash, r_hash, count)` — same forge-resistance as the aggregate path's `HashWithCount` collapse. The SDK's [`drive_proof_verifier::verify_distinct_count_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) runs the standard hash-chain check, then walks the proof's op stream to extract the counts as a `BTreeMap, u64>`. Trade-off vs. the aggregate path: proof size is O(distinct values matched) rather than O(log n), because each distinct in-range key emits its own `KVCount` op instead of being collapsed into a boundary subtree. Acceptable for typical histograms (a few dozen distinct values in range); for "give me a single count" use the aggregate path instead. **Without a range clause** (point-lookup with prove): two sub-paths based on the request shape. -- **Unfiltered total + `documentsCountable: true`**: drive-abci proves the doctype's primary-key `CountTree` element at `[contract_doc, contract_id, 1, doctype, 0]`. One merk path proof; the SDK's [`drive_proof_verifier::verify_primary_key_count_tree_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) reads `count_value` off the verified element. O(log n) bytes. +- **Unfiltered total + `documentsCountable: true`**: drive-abci proves the doctype's primary-key `CountTree` element at `[contract_doc, contract_id, 1, doctype, 0]`. One merk path proof; the SDK's [`drive_proof_verifier::verify_primary_key_count_tree_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) reads `count_value` off the verified element. O(log n) bytes. - **Equal/In against a fully-covering `countable: true` index**: drive-abci proves one `Element::CountTree` per covered branch. Two sub-shapes: - **Equal-only fully-covered** → one element at `[..., last_field, last_value, 0]`. - **`In` at any index position (with any number of trailing Equals)** → one element per In value, fetched via outer Query + a subquery whose `set_subquery_path` carries the post-In Equal segments (zero of them when In is on the last property; one or more when In sits earlier in the index). The subquery's `Key([0])` picks off the CountTree at `[..., in_field, in_value, , 0]` for each matched In branch. - The In position rule for count queries is **more permissive than the regular document query path's `Index::matches`** rule (which restricts In to last-or-before-last because of a positional path-construction assumption — see `DriveDocumentQuery::get_non_primary_key_path_query` for the layout that forces it). The count path doesn't have that constraint: there's no document-key terminator descent, no `order_by` interpretation, and no `limit/offset` semantics — it's a pure CountTree-element lookup, so `set_subquery_path` with an arbitrary trailing tail works. Both no-proof and prove count executors route through a single `point_lookup_count_path_query` builder (no-proof runs the path query via `grove.query` and sums the emitted `CountTree` elements' counts; prove signs the same path query via `get_proved_path_query`), so they accept the same query shapes by construction. The SDK's [`drive_proof_verifier::verify_point_lookup_count_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) verifies and extracts `count_value_or_default()` from each verified element. + The In position rule for count queries is **more permissive than the regular document query path's `Index::matches`** rule (which restricts In to last-or-before-last because of a positional path-construction assumption — see `DriveDocumentQuery::get_non_primary_key_path_query` for the layout that forces it). The count path doesn't have that constraint: there's no document-key terminator descent, no `order_by` interpretation, and no `limit/offset` semantics — it's a pure CountTree-element lookup, so `set_subquery_path` with an arbitrary trailing tail works. Both no-proof and prove count executors route through a single `point_lookup_count_path_query` builder (no-proof runs the path query via `grove.query` and sums the emitted `CountTree` elements' counts; prove signs the same path query via `get_proved_path_query`), so they accept the same query shapes by construction. The SDK's [`drive_proof_verifier::verify_point_lookup_count_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) verifies and extracts `count_value_or_default()` from each verified element. Both sub-paths share the proof shape: each CountTree element's `count_value` is cryptographically bound to the merk root via `node_hash_with_count(kv_hash, l_hash, r_hash, count)`, same forge-resistance guarantee the range-distinct path relies on. Neither materializes documents or runs per-key bookkeeping client-side. @@ -172,9 +172,9 @@ Proof size: **O(k × log n)** where k is the number of covered branches (1 for t **Symmetric rejection contract**: prove count requires a `countable: true` index whose properties exactly match the where clauses — same requirement as the no-proof `Total` / `PerInValue` modes. Partial coverage (where the where clauses are a strict prefix of the index, or the index has uncovered properties) rejects with a `WhereClauseOnNonIndexedProperty`-class error pointing the caller at the index-design fix. The `documents_countable: true` fast path handles unfiltered total counts in O(log n) proof bytes when set on the document type. No silent fallback to materializing matching documents — that path doesn't exist anymore. Implementation reference: -- Path query: [`DriveDocumentCountQuery::point_lookup_count_path_query`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/path_query.rs) — shared by prover and verifier. -- Server executor: [`DriveDocumentCountQuery::execute_point_lookup_count_with_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/execute_point_lookup.rs). -- Verifier: [`DriveDocumentCountQuery::verify_point_lookup_count_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/verify/document_count/verify_point_lookup_count_proof/mod.rs); SDK wrapper [`drive_proof_verifier::verify_point_lookup_count_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) composes tenderdash signature verification on top. +- Path query: [`DriveDocumentCountQuery::point_lookup_count_path_query`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/path_query.rs) — shared by prover and verifier. +- Server executor: [`DriveDocumentCountQuery::execute_point_lookup_count_with_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/execute_point_lookup.rs). +- Verifier: [`DriveDocumentCountQuery::verify_point_lookup_count_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/verify/document_count/verify_point_lookup_count_proof/mod.rs); SDK wrapper [`drive_proof_verifier::verify_point_lookup_count_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs) composes tenderdash signature verification on top. ### Supported Where Operators @@ -386,7 +386,7 @@ A few notes about the index-level flag: | O(1) filtered count: `count(*) WHERE col = X` | `countable: true` on an index whose properties are exactly `["col"]`. A composite index whose leading column is `col` (e.g. `["col", "other"]`) does NOT answer this query — partial coverage rejects with `WhereClauseOnNonIndexedProperty`. Define a separate `["col"]` countable index if you want this count. | | Per-`In`-value sub-counts: one `CountEntry` per value in an `In` clause | `countable: true` on an index whose properties exactly match the query's `==` clauses plus the `In` field. **The `In` field may sit at any position in the index** — both the no-proof and prove count paths use `set_subquery_path` to descend through any trailing Equals after the In, which is strictly more permissive than the regular document query path's last-or-before-last rule. E.g. `WHERE color IN [...]` needs `["color"]`; `WHERE brand = X AND color IN [...]` needs `["brand", "color"]`; `WHERE brand IN [...] AND model = X AND year = 2024` needs `["brand", "model", "year"]` with In on `brand` (position 0 of 3). | | O(log n) range count: `count(*) WHERE col BETWEEN A AND B` | `rangeCountable: true` on an index whose last property is `col` and whose other properties cover any equality predicates as a prefix. Implies `countable: true`. | -| Per-distinct-value range histogram: one `CountEntry` per distinct value in a range | Same `rangeCountable: true` index as above, plus `return_distinct_counts_in_range = true` on the request. Available on both prove and no-prove paths; the prove path returns a regular range proof against the property-name `ProvableCountTree` and the SDK extracts per-key counts from the proof's `KVCount` ops via [`drive_proof_verifier::verify_distinct_count_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs). | +| Per-distinct-value range histogram: one `CountEntry` per distinct value in a range | Same `rangeCountable: true` index as above, plus `return_distinct_counts_in_range = true` on the request. Available on both prove and no-prove paths; the prove path returns a regular range proof against the property-name `ProvableCountTree` and the SDK extracts per-key counts from the proof's `KVCount` ops via [`drive_proof_verifier::verify_distinct_count_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive-proof-verifier/src/proof/document_count.rs). | | Range count proof (`prove = true` + range clause) | Same `rangeCountable: true` index. The handler uses grovedb's `AggregateCountOnRange` proof primitive — proof is O(log n), no cap on matched docs. | | Future offset-style range queries (not yet released — see above) | `rangeCountable: true` on the document type | | Nothing count-aware (default) | Don't set any of these flags. Primary-key tree stays a `NormalTree`. | diff --git a/book/src/drive/document-sum-trees.md b/book/src/drive/document-sum-trees.md index a419fd2c59..932b240704 100644 --- a/book/src/drive/document-sum-trees.md +++ b/book/src/drive/document-sum-trees.md @@ -2,7 +2,7 @@ Summing a numeric property across the documents that match a query used to mean fetching them all and adding values up client-side. The grovedb upgrade that landed alongside [Document Count Trees](./document-count-trees.md) adds **provable sum trees** and **references with sum item** as primitives — the building blocks Drive uses to turn `sum(amount)`-style queries into an O(log n) provable lookup. This chapter explains the three sum-tree variants, how a document type opts into one, the unified `GetDocumentsSum` endpoint that exposes the feature, and the parallels with the count-tree machinery. -> **Status:** the grovedb-level sum-tree primitives (`SumTree`, `ProvableSumTree`, `BigSumTree`, and reference elements that carry a sum-item contribution) are in place. The Drive-level schema syntax, query handler, and SDK surfaces described below are the proposed design — the [Sum Index Examples](./sum-index-examples.md) chapter is the worked-example companion, and the tip-jar contract fixture at [`packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json) is the schema this design targets. +> **Status:** the grovedb-level sum-tree primitives (`SumTree`, `ProvableSumTree`, `BigSumTree`, and reference elements that carry a sum-item contribution) are in place. The Drive-level schema syntax, query handler, and SDK surfaces described below are the proposed design — the [Sum Index Examples](./sum-index-examples.md) chapter is the worked-example companion, and the tip-jar contract fixture at [`packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json) is the schema this design targets. ## Why Sum Trees Exist @@ -124,7 +124,7 @@ The two-path / two-shape split is identical to the count endpoint's, and for the ### No-Prove (Server-Side O(1) or O(log n)) -When `prove=false`, drive-abci calls into `DriveDocumentSumQuery` (the proposed analog of `DriveDocumentCountQuery` in [`packages/rs-drive/src/query/drive_document_count_query/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/mod.rs)). The handler picks a path based on the where clauses: +When `prove=false`, drive-abci calls into `DriveDocumentSumQuery` (the proposed analog of `DriveDocumentCountQuery` in [`packages/rs-drive/src/query/drive_document_count_query/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/mod.rs)). The handler picks a path based on the where clauses: **Unfiltered total (no where clauses) on a `documentsSummable: "amount"` document type**: diff --git a/book/src/drive/indexes.md b/book/src/drive/indexes.md index c316904529..bc8e026ae4 100644 --- a/book/src/drive/indexes.md +++ b/book/src/drive/indexes.md @@ -32,7 +32,7 @@ Concrete example. Given: ## The `Index` Struct -The compiled-Rust shape — the JSON schema fields are deserialized into this — lives in [`packages/rs-dpp/src/data_contract/document_type/index/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-dpp/src/data_contract/document_type/index/mod.rs): +The compiled-Rust shape — the JSON schema fields are deserialized into this — lives in [`packages/rs-dpp/src/data_contract/document_type/index/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-dpp/src/data_contract/document_type/index/mod.rs): ```rust pub struct Index { @@ -122,7 +122,7 @@ The schema accepts both the legacy boolean form (`true` → `Countable`, `false` ## How Drive Builds the IndexLevel Trie -The flat list of `Index`es declared on a document type is compiled, at contract-load time, into an `IndexLevel` trie ([`packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs)): +The flat list of `Index`es declared on a document type is compiled, at contract-load time, into an `IndexLevel` trie ([`packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs)): ```rust pub struct IndexLevel { @@ -468,7 +468,7 @@ Count trees automatically count *every* child element. A `NormalTree`, an `Item` Sum trees behave the opposite way. Only sum-bearing element variants — `SumItem`, `ItemWithSumItem`, `ReferenceWithSumItem`, and the sum-bearing tree variants themselves — contribute to a parent `SumTree`'s running sum. `Item`, `Reference`, plain `NormalTree`, `CountTree` — all contribute **0** by default. That has two consequences: -1. **Per-document contributions don't appear automatically.** A plain `Element::Reference` under a `SumTree` does not propagate any sum. We need a different reference element — `Element::ReferenceWithSumItem(path, max_hops, sum_value, flags)` — that carries an explicit `i64` sum contribution (the document's value at the `summable` property, frozen at insert time) alongside the usual reference-path bytes. Grovedb PR 670 adds this variant; Drive's index walker constructs it via [`make_document_reference_with_sum_item`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/mod.rs) under any index path with `summable.is_some()`. +1. **Per-document contributions don't appear automatically.** A plain `Element::Reference` under a `SumTree` does not propagate any sum. We need a different reference element — `Element::ReferenceWithSumItem(path, max_hops, sum_value, flags)` — that carries an explicit `i64` sum contribution (the document's value at the `summable` property, frozen at insert time) alongside the usual reference-path bytes. Grovedb PR 670 adds this variant; Drive's index walker constructs it via [`make_document_reference_with_sum_item`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/mod.rs) under any index path with `summable.is_some()`. 2. **Sibling continuations usually don't need a wrapper.** A `NormalTree` continuation under a sum-bearing value tree contributes 0 by default — exactly what we want. No `NotSummed` wrap required. The exception is when the continuation is *itself* sum-bearing (e.g. a deeper compound index that's also `range_summable`); in that case wrap the continuation in `Element::NotSummed<*>` to keep its sum from leaking into the outer index's aggregate. Compare with `range_countable`, where **every** continuation needs `NonCounted` because every non-count-aware element auto-contributes 1. #### Layout @@ -509,7 +509,7 @@ Extend the widget contract with a numeric `price` property and promote both inde Both indexes name **the same** sum property — `summable: "price"` in both. The DPP validator requires this: grovedb's sum trees aggregate `i64` per merk node with no per-tree property tag, so a contract that mixed `summable: "price"` and `summable: "fee"` on the same doctype would feed inconsistent contributions into the same merk hierarchy. `price` is `type: integer` and listed in `required` — both also enforced at contract-creation time. -`byColorShape` combines `countable` (root-only doc count per `(color, shape)` pair) with `summable` + `rangeSummable` (per-node sums of `price`). Drive's dispatch table promotes this combination to **`ProvableCountProvableSumTree`** (PCPS) at the value-tree and `[0]` terminal levels — the only grovedb variant carrying per-node sums also carries per-node counts as a side effect, so the count side gets per-node tracking "for free" even though only the sum side was opted into provability. See [`DocumentTypePrimaryKeyTreeType::primary_key_tree_type`'s v1 dispatch table](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs) for the full mapping. +`byColorShape` combines `countable` (root-only doc count per `(color, shape)` pair) with `summable` + `rangeSummable` (per-node sums of `price`). Drive's dispatch table promotes this combination to **`ProvableCountProvableSumTree`** (PCPS) at the value-tree and `[0]` terminal levels — the only grovedb variant carrying per-node sums also carries per-node counts as a side effect, so the count side gets per-node tracking "for free" even though only the sum side was opted into provability. See [`DocumentTypePrimaryKeyTreeType::primary_key_tree_type`'s v1 dispatch table](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs) for the full mapping. The two indexes share the `color` prefix exactly as the count examples did, so the same shared-prefix layout still applies. What changes is the element types at every level from `'color'` downward — and the diagram below makes the compound case visible, because the `'shape'` continuation under each color is now *itself* a sum-bearing tree (since `byColorShape` is `rangeSummable`) and needs `Element::NotSummed<*>`-wrapping to keep its aggregate from leaking into the outer `byColor` sum. @@ -608,7 +608,7 @@ Walking through how the aggregates layer: ##### Why PCPS at the value level -PCPS is grovedb's only tree variant carrying per-node sums. When an index sets `countable: "" + summable + rangeSummable`, the dispatch table promotes the value tree to PCPS because there's no "ProvableSumCountTree" variant (per-node sum + root-only count) to land on. The count side gets per-node tracking "for free" — same storage cost as `ProvableCountSumTree`'s count-half since PCPS commits the same per-node count metadata. See [`primary_key_tree_type.rs`'s v1 dispatch table](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs) for the full mapping. +PCPS is grovedb's only tree variant carrying per-node sums. When an index sets `countable: "" + summable + rangeSummable`, the dispatch table promotes the value tree to PCPS because there's no "ProvableSumCountTree" variant (per-node sum + root-only count) to land on. The count side gets per-node tracking "for free" — same storage cost as `ProvableCountSumTree`'s count-half since PCPS commits the same per-node count metadata. See [`primary_key_tree_type.rs`'s v1 dispatch table](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs) for the full mapping. `byColor`, by contrast, has only `summable + rangeSummable` (no `countable`), so its value trees stay `SumTree` — root-only sum, no count tracking, no upgrade. The two indexes living side by side on the same widget contract show both sides of the dispatch. @@ -648,13 +648,13 @@ Setting both `range_countable: true` AND `range_summable: true` on the same inde The combined primitive is strictly cheaper than running two separate range queries: one proof envelope, one merk walk, and both metrics atomically bound to the same root hash (so they can't drift relative to each other across a concurrent write). -The full dispatch table mapping `(countable, range_countable, summable, range_summable)` combinations to grovedb tree variants lives in [`DocumentTypePrimaryKeyTreeType::primary_key_tree_type`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs)'s v1 arm; the index-walker dispatch in [`add_indices_for_index_level_for_contract_operations`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations) follows the same table at every recursion level. +The full dispatch table mapping `(countable, range_countable, summable, range_summable)` combinations to grovedb tree variants lives in [`DocumentTypePrimaryKeyTreeType::primary_key_tree_type`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/primary_key_tree_type.rs)'s v1 arm; the index-walker dispatch in [`add_indices_for_index_level_for_contract_operations`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations) follows the same table at every recursion level. -End-to-end coverage for the sum surface lives in [`packages/rs-drive/benches/document_sum_worst_case.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_sum_worst_case.rs)'s tip-jar fixture (paralleling the count side's `document_count_worst_case.rs` widget bench), with the worked-example queries in [Sum Index Examples](sum-index-examples.md). +End-to-end coverage for the sum surface lives in [`packages/rs-drive/benches/document_sum_worst_case.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_sum_worst_case.rs)'s tip-jar fixture (paralleling the count side's `document_count_worst_case.rs` widget bench), with the worked-example queries in [Sum Index Examples](sum-index-examples.md). ## Tree Type at the Terminal Level -The decision happens in [`add_reference_for_index_level_for_contract_operations/v0/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs): +The decision happens in [`add_reference_for_index_level_for_contract_operations/v0/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs): ```rust if !index_type.index_type.is_unique() || any_fields_null { @@ -722,7 +722,7 @@ Same convention as the layout diagram above: rectangles are tree-type elements, ## Null Handling -The `any_fields_null` and `all_fields_null` flags are accumulated as Drive descends the index property list during insertion ([`add_indices_for_index_level_for_contract_operations/v0/mod.rs:170-171`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs#L170-L171)): +The `any_fields_null` and `all_fields_null` flags are accumulated as Drive descends the index property list during insertion ([`add_indices_for_index_level_for_contract_operations/v0/mod.rs:170-171`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs#L170-L171)): ```rust any_fields_null |= document_index_field.is_empty(); @@ -747,11 +747,11 @@ Putting it together, when Drive inserts a document into a contract `C` of type ` 2. **`add_indices_for_index_level_for_contract_operations`** (recursive) — for each sub-level of the trie, pushes the property name and value onto the path, OR-accumulates `any_fields_null`, AND-accumulates `all_fields_null`, and recurses. If the current level has `has_index_with_type = Some(...)`, it also calls into step 3 *before* recursing further (because an index can terminate at a non-leaf trie level when another index continues past it). 3. **`add_reference_for_index_level_for_contract_operations`** — the terminal call. Decides between unique and non-unique-style storage using the matrix above; for the non-unique-style path it picks a `NormalTree` / `CountTree` / `ProvableCountTree` based on `countable`; finally inserts the document reference (or sub-tree containing it). -Deletion mirrors the same walk in reverse — see [`packages/rs-drive/src/drive/document/delete/`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/drive/document/delete/). +Deletion mirrors the same walk in reverse — see [`packages/rs-drive/src/drive/document/delete/`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/drive/document/delete/). ## Query Traversal -When a query arrives at drive-abci, the document-query construction path picks one of the document type's indexes that "covers" the query — i.e., whose property prefix matches the query's equality clauses, in order. The picker is in [`packages/rs-drive/src/query/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/mod.rs) (look for `fn construct_path_query` and the index-selection helpers it calls). For count queries specifically there's a separate, count-tree-aware picker ([`drive_document_count_query/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_count_query/mod.rs)) — see [Document Count Trees](document-count-trees.md) for that path. +When a query arrives at drive-abci, the document-query construction path picks one of the document type's indexes that "covers" the query — i.e., whose property prefix matches the query's equality clauses, in order. The picker is in [`packages/rs-drive/src/query/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/mod.rs) (look for `fn construct_path_query` and the index-selection helpers it calls). For count queries specifically there's a separate, count-tree-aware picker ([`drive_document_count_query/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_count_query/mod.rs)) — see [Document Count Trees](document-count-trees.md) for that path. Once an index is picked, the query-engine builds a `PathQuery` whose path is exactly the prefix shape the insert code produced: `[DataContractDocuments, contract_id, 1, doc_type, prop, value, prop, value, …]`. GroveDB then walks the path in O(log n per level), reading the terminal sub-tree (or single reference) and returning matching documents. diff --git a/book/src/drive/sum-index-examples.md b/book/src/drive/sum-index-examples.md index c1c6e2a8ab..48b5509f91 100644 --- a/book/src/drive/sum-index-examples.md +++ b/book/src/drive/sum-index-examples.md @@ -1,10 +1,10 @@ # Sum Index Examples -This chapter walks through a representative contract and shows what a sum-query proof actually proves — both the path query the prover signs and the verified element the verifier extracts. Every example uses the same `tip` document type on the **tip-jar contract** at [`packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json), so the proof bytes, verified elements, and diagrams can all be cross-referenced against the same data once the bench fixture lands. +This chapter walks through a representative contract and shows what a sum-query proof actually proves — both the path query the prover signs and the verified element the verifier extracts. Every example uses the same `tip` document type on the **tip-jar contract** at [`packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/tests/supporting_files/contract/tip-jar/tip-jar-contract.json), so the proof bytes, verified elements, and diagrams can all be cross-referenced against the same data once the bench fixture lands. The chapter assumes you've read [Document Sum Trees](./document-sum-trees.md) — that chapter explains the three tree variants (`NormalTree` / `SumTree` / `ProvableSumTree`), how `Element::NonCounted`-style "doesn't contribute to my parent's aggregation" wrappers work (now for sums as well), and how the schema's `documentsSummable` / `rangeSummable` flags select between them. Here we take that machinery as given and trace what each query *sees*. -> **Status:** the bench at [`packages/rs-drive/benches/document_sum_worst_case.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/benches/document_sum_worst_case.rs) lands the reproducible numbers below — same convention as the [Count Index Examples](./count-index-examples.md) chapter. All proof sizes are measured against a 100 000-row fixture; verified `sum` values are the actual sums the bench's matrix reports. The full surface — primary-key total, point lookups, In-fan-out, `AggregateSumOnRange` on both top-level and compound indexes, and the carrier-aggregate primitive from grovedb PR #670 — is fully wired and producing the byte counts in the table below. +> **Status:** the bench at [`packages/rs-drive/benches/document_sum_worst_case.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/benches/document_sum_worst_case.rs) lands the reproducible numbers below — same convention as the [Count Index Examples](./count-index-examples.md) chapter. All proof sizes are measured against a 100 000-row fixture; verified `sum` values are the actual sums the bench's matrix reports. The full surface — primary-key total, point lookups, In-fan-out, `AggregateSumOnRange` on both top-level and compound indexes, and the carrier-aggregate primitive from grovedb PR #670 — is fully wired and producing the byte counts in the table below. ## The Tip Jar Contract @@ -1543,7 +1543,7 @@ sum_property = "amount" prove = true ``` -This is the **carrier-aggregate sum** shape: an `In` clause on the index's prefix property combined with a range on its terminator, returning **one sum per resolved In-bucket** rather than a single aggregate across all matches. The `group_by = [recipient]` (not `[recipient, sentAt]`) routes through `SumMode::GroupByIn` — the routing table at [`mode_detection/v0/mod.rs`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/query/drive_document_sum_query/mode_detection/v0/mod.rs) maps `(GroupByIn, In, range, prove) → RangeAggregateCarrierProof`, which is what the per-In-bucket aggregation needs. A `group_by = [recipient, sentAt]` (`GroupByCompound`) routes to `RangeDistinctProof` instead — per-`(in_key, range_key)` distinct walk, a different proof shape entirely. Sum analog of count's [Range-Countable group-by carrier-aggregate](./count-index-examples.md#range-countable-group-by-carrier-aggregate). The primitive landed in [grovedb PR #670](https://github.com/dashpay/grovedb/pull/670) (head `e98bab5f`); the verifier is [`GroveDb::verify_aggregate_sum_query_per_key`](https://github.com/dashpay/grovedb/blob/e98bab5f/grovedb/src/operations/proof/aggregate_sum/mod.rs). +This is the **carrier-aggregate sum** shape: an `In` clause on the index's prefix property combined with a range on its terminator, returning **one sum per resolved In-bucket** rather than a single aggregate across all matches. The `group_by = [recipient]` (not `[recipient, sentAt]`) routes through `SumMode::GroupByIn` — the routing table at [`mode_detection/v0/mod.rs`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/query/drive_document_sum_query/mode_detection/v0/mod.rs) maps `(GroupByIn, In, range, prove) → RangeAggregateCarrierProof`, which is what the per-In-bucket aggregation needs. A `group_by = [recipient, sentAt]` (`GroupByCompound`) routes to `RangeDistinctProof` instead — per-`(in_key, range_key)` distinct walk, a different proof shape entirely. Sum analog of count's [Range-Countable group-by carrier-aggregate](./count-index-examples.md#range-countable-group-by-carrier-aggregate). The primitive landed in [grovedb PR #670](https://github.com/dashpay/grovedb/pull/670) (head `e98bab5f`); the verifier is [`GroveDb::verify_aggregate_sum_query_per_key`](https://github.com/dashpay/grovedb/blob/e98bab5f/grovedb/src/operations/proof/aggregate_sum/mod.rs). **Path query** (carrier-style: outer Query enumerates the In branches, subquery descends through the terminator's `AggregateSumOnRange`): @@ -1967,7 +1967,7 @@ The two carrier-aggregate gates worth knowing: - **`SizedQuery::limit`** caps the outer walk (here `limit = 100` accommodates all distinct recipients; for an open-ended outer `Range` clause it bounds how many In-branches the proof commits). The verifier rebuilds the same `limit` byte-for-byte; mismatched limits break the merk-root recomputation. - **`SizedQuery::offset`** is rejected for carrier-aggregate (would change which `(outer_key, sum)` pairs end up in the proof; the use case isn't designed yet). Mirrors the count-side carrier-ACOR contract. -The PCPS variant — `AggregateCountAndSumOnRange` on a carrier — exists too; same primitive, but returns `(outer_key, u64 count, i64 sum)` triples for indexes that opt into both `rangeCountable: true` and `rangeSummable: true`. Drive-side support is wired ([`DriveDocumentSumQuery::verify_carrier_aggregate_count_and_sum_proof`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-drive/src/verify/document_sum/verify_carrier_aggregate_count_and_sum_proof)); a worked PCPS-carrier example will live in a separate combined-feature chapter alongside its own contract. +The PCPS variant — `AggregateCountAndSumOnRange` on a carrier — exists too; same primitive, but returns `(outer_key, u64 count, i64 sum)` triples for indexes that opt into both `rangeCountable: true` and `rangeSummable: true`. Drive-side support is wired ([`DriveDocumentSumQuery::verify_carrier_aggregate_count_and_sum_proof`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-drive/src/verify/document_sum/verify_carrier_aggregate_count_and_sum_proof)); a worked PCPS-carrier example will live in a separate combined-feature chapter alongside its own contract. ## Range Modes — Distinct Variant diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerShieldedSync.swift b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerShieldedSync.swift index 7d2429b56c..c2990270cd 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerShieldedSync.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerShieldedSync.swift @@ -28,7 +28,7 @@ public struct ShieldedIdentityCreateUnconfirmedError: LocalizedError { /// Per-wallet outcome from a completed shielded sync pass. /// /// Mirrors the Rust-side -/// [`ShieldedSyncWalletResultFFI`](https://github.com/dashpay/platform/blob/v3.1-dev/packages/rs-platform-wallet-ffi/src/shielded_types.rs) +/// [`ShieldedSyncWalletResultFFI`](https://github.com/dashpay/platform/blob/v4.0-dev/packages/rs-platform-wallet-ffi/src/shielded_types.rs) /// with three states: /// /// - `success == true`: sync succeeded; the numeric counters are From 9f9092cc910809fd5c415b74fe939864d7bfa7ed Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 1 Jul 2026 19:31:49 +0700 Subject: [PATCH 3/3] chore(release): update changelog and bump version to 4.0.0 (#3975) Co-authored-by: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 120 ++++++++++++++++++ Cargo.lock | 86 ++++++------- Cargo.toml | 2 +- package.json | 2 +- packages/bench-suite/package.json | 2 +- packages/dapi-grpc/package.json | 2 +- packages/dapi/package.json | 2 +- packages/dash-spv/package.json | 2 +- .../configs/getConfigFileMigrationsFactory.js | 15 +++ packages/dashmate/package.json | 2 +- .../migrateConfigFileFactory.spec.js | 40 ++++++ packages/dashpay-contract/package.json | 2 +- packages/dpns-contract/package.json | 2 +- packages/js-dapi-client/package.json | 2 +- packages/js-dash-sdk/package.json | 2 +- packages/js-evo-sdk/package.json | 2 +- packages/js-grpc-common/package.json | 2 +- packages/keyword-search-contract/package.json | 2 +- .../package.json | 2 +- packages/platform-test-suite/package.json | 2 +- packages/token-history-contract/package.json | 2 +- packages/wallet-lib/package.json | 2 +- packages/wallet-utils-contract/package.json | 2 +- packages/wasm-dpp/package.json | 2 +- packages/wasm-dpp2/package.json | 2 +- packages/wasm-drive-verify/package.json | 2 +- packages/wasm-sdk/package.json | 2 +- packages/withdrawals-contract/package.json | 2 +- 28 files changed, 242 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eb5c6bb52..fb22a803da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,123 @@ +## [4.0.0](https://github.com/dashpay/platform/compare/v4.0.0-rc.2...v4.0.0) (2026-07-01) + + +### ⚠ BREAKING CHANGES + +* **dpp:** make platform/orchard address decoders network-agnostic (#3781) + +### Features + +* **contract:** on-chain QA framework storage layer (testCase + testRun) ([#3910](https://github.com/dashpay/platform/issues/3910)) +* **dpp:** add getters and setters for new shielded state transitions ([#3879](https://github.com/dashpay/platform/issues/3879)) +* **platform-wallet:** external signable wallets ([#3639](https://github.com/dashpay/platform/issues/3639)) +* **platform:** shielded transaction history ([#3870](https://github.com/dashpay/platform/issues/3870)) +* record DAPI address ban reason and expose via platform-wallet FFI ([#3890](https://github.com/dashpay/platform/issues/3890)) +* **rs-sdk-ffi:** add masternode contested-resource vote broadcast (FFI + Swift UI) ([#3883](https://github.com/dashpay/platform/issues/3883)) +* **rs-sdk-ffi:** expose dash_sdk_signer_can_sign for signer-delegated key preflight ([#3924](https://github.com/dashpay/platform/issues/3924)) +* **sdk:** implement document sum/average aggregation FFI (DOC-13/14) ([#3935](https://github.com/dashpay/platform/issues/3935)) +* **swift-example-app:** add identity→identity Transfer Credits production UI ([#3891](https://github.com/dashpay/platform/issues/3891)) +* **swift-example-app:** add production Disable Key action with safety gates (ID-12) ([#3918](https://github.com/dashpay/platform/issues/3918)) +* **swift-example-app:** document count aggregation view (DOC-10/11/12) ([#3926](https://github.com/dashpay/platform/issues/3926)) +* **swift-example-app:** document sum/average aggregation view (DOC-13/14) ([#3942](https://github.com/dashpay/platform/issues/3942)) +* **swift-example-app:** GroveDB path elements diagnostic view (SYS-06) ([#3931](https://github.com/dashpay/platform/issues/3931)) +* **swift-example-app:** multi-recipient Core L1 send (CORE-10) ([#3904](https://github.com/dashpay/platform/issues/3904)) +* **swift-example-app:** one-tap testnet DASH faucet button ([#3905](https://github.com/dashpay/platform/issues/3905)) +* **swift-example-app:** production document replace/delete/transfer/price/purchase UI (DOC-03..07) ([#3945](https://github.com/dashpay/platform/issues/3945)) +* **swift-example-app:** production Withdraw Credits UI on identity detail (ID-10) ([#3906](https://github.com/dashpay/platform/issues/3906)) +* **swift-example-app:** rebrand to "Dash Developer Pro" for TestFlight ([#3952](https://github.com/dashpay/platform/issues/3952)) +* **swift-example-app:** send from Core balance to a shielded recipient ([#3885](https://github.com/dashpay/platform/issues/3885)) +* **swift-sdk:** add BIP39 word-validation helpers for the recover flow ([#3842](https://github.com/dashpay/platform/issues/3842)) +* **swift-sdk:** add identityUpdate handler to the generic transition builder ([#3880](https://github.com/dashpay/platform/issues/3880)) +* **swift-sdk:** add production create-document flow via platform-wallet FFI ([#3908](https://github.com/dashpay/platform/issues/3908)) +* **swift-sdk:** log tokio runtime metrics from rs-sdk-ffi and platform-wallet-ffi ([#3901](https://github.com/dashpay/platform/issues/3901)) +* **swift-sdk:** wire data contract update through the platform-wallet path ([#3882](https://github.com/dashpay/platform/issues/3882)) + + +### Bug Fixes + +* **dashmate:** use active_dkgs for safe DKG stop ([#3941](https://github.com/dashpay/platform/issues/3941)) +* **dpp:** enforce byte array encoding stability in data contract updates ([#3868](https://github.com/dashpay/platform/issues/3868)) +* **dpp:** guard index property parsing against empty/oversized maps to prevent check_tx panic ([#3866](https://github.com/dashpay/platform/issues/3866)) +* **dpp:** make platform/orchard address decoders network-agnostic ([#3781](https://github.com/dashpay/platform/issues/3781)) +* **dpp:** reject empty token pricing schedules to prevent a direct-purchase chain halt ([#3865](https://github.com/dashpay/platform/issues/3865)) +* **drive:** return empty history for contracts that don't keep history ([#3884](https://github.com/dashpay/platform/issues/3884)) +* **drive:** unify shielded per-action processing fee across all protocol versions ([#3877](https://github.com/dashpay/platform/issues/3877)) +* **platform-wallet:** add TRANSFER key to default identity registration key set ([#3894](https://github.com/dashpay/platform/issues/3894)) +* **platform-wallet:** apply disabled-key flags to local cache after identity update ([#3915](https://github.com/dashpay/platform/issues/3915)) +* **platform-wallet:** build data contract config at the protocol-required version ([#3881](https://github.com/dashpay/platform/issues/3881)) +* **platform-wallet:** free SPV data dir on stop ([#3811](https://github.com/dashpay/platform/issues/3811)) +* **platform-wallet:** spv error propagation ([#3810](https://github.com/dashpay/platform/issues/3810)) +* **rs-sdk-ffi:** classify DAPI transport and timeout errors instead of internalError ([#3916](https://github.com/dashpay/platform/issues/3916)) +* **rs-sdk-ffi:** don't export ContestedResourceVoteChoiceFFI to the C header ([#3892](https://github.com/dashpay/platform/issues/3892)) +* **rs-sdk-ffi:** run blocking FFI calls on a large stack to prevent proof-verification stack overflow ([#3896](https://github.com/dashpay/platform/issues/3896)) +* **rs-sdk-ffi:** stop labeling unclassified SDK errors as "failed to fetch balances" ([#3878](https://github.com/dashpay/platform/issues/3878)) +* **rs-sdk:** case-insensitive .dash suffix in DPNS name resolution ([#3914](https://github.com/dashpay/platform/issues/3914)) +* **sdk:** ban node and retry elsewhere on UNIMPLEMENTED responses ([#3875](https://github.com/dashpay/platform/issues/3875)) +* **sdk:** ban rate-limited node for Envoy-advertised reset window ([#3951](https://github.com/dashpay/platform/issues/3951)) +* **sdk:** default initial protocol version to 10 when unpinned (upgrade-safe ratchet floor) ([#3809](https://github.com/dashpay/platform/issues/3809)) +* **sdk:** default to latest protocol version instead of pinning testnet to v1 ([#3937](https://github.com/dashpay/platform/issues/3937)) +* **sdk:** refresh protocol version via a proven query, not unproved getStatus ([#3893](https://github.com/dashpay/platform/issues/3893)) +* **sdk:** refresh SDK protocol version to the network's on startup and network switch ([#3886](https://github.com/dashpay/platform/issues/3886)) +* **sdk:** verify quorum signature on broadcast wait-path before trusting metadata ([#3872](https://github.com/dashpay/platform/issues/3872)) +* **swift-example-app:** expose Picker options to UI automation ([#3903](https://github.com/dashpay/platform/issues/3903)) +* **swift-example-app:** fix compile timeout on on newest xcode versions ([#3899](https://github.com/dashpay/platform/issues/3899)) +* **swift-example-app:** harden Withdraw Credits amount + address validation ([#3907](https://github.com/dashpay/platform/issues/3907)) +* **swift-example-app:** load document price on Purchase sheet appear ([#3947](https://github.com/dashpay/platform/issues/3947)) +* **swift-example-app:** prevent UInt64.max overflow crash in TransferCreditsView amount parsing ([#3909](https://github.com/dashpay/platform/issues/3909)) +* **swift-example-app:** show success title on DPNS registration alert ([#3873](https://github.com/dashpay/platform/issues/3873)) +* **swift-sdk:** keychain priv key storage indexes by label ([#3946](https://github.com/dashpay/platform/issues/3946)) +* **swift-sdk:** make Document transition contract/type pickers idb-drivable ([#3921](https://github.com/dashpay/platform/issues/3921)) +* **swift-sdk:** parse getIdentitiesTokenBalances NSNumber result ([#3943](https://github.com/dashpay/platform/issues/3943)) +* **swift-sdk:** seed testnet at the per-network protocol-version floor instead of pinning PV11 ([#3944](https://github.com/dashpay/platform/issues/3944)) +* **swift-sdk:** sign document state transitions with an available AUTHENTICATION key ([#3922](https://github.com/dashpay/platform/issues/3922)) +* **swift-sdk:** stamp firstSeen at insert for unconfirmed transactions ([#3874](https://github.com/dashpay/platform/issues/3874)) +* **swift-sdk:** update token balance from the transfer/burn proof result (MW-02) ([#3934](https://github.com/dashpay/platform/issues/3934)) +* **wasm-sdk:** preserve user-supplied addresses in withTrustedContext ([#3912](https://github.com/dashpay/platform/issues/3912)) + + +### Continuous Integration + +* **swift-sdk:** remove swift-sdk artifact upload ([#3778](https://github.com/dashpay/platform/issues/3778)) + + +### Documentation + +* **swift-example-app:** add MANUAL tier to iOS test plan ([#3895](https://github.com/dashpay/platform/issues/3895)) +* **swift-example-app:** add multi-wallet test cases (Core + Platform) to iOS test plan ([#3888](https://github.com/dashpay/platform/issues/3888)) +* **swift-example-app:** add tiered iOS feature test plan ([#3887](https://github.com/dashpay/platform/issues/3887)) +* **swift-example-app:** link on-chain QA status dashboard from TEST_PLAN ([#3911](https://github.com/dashpay/platform/issues/3911)) +* **swift-example-app:** re-tier + re-status SH-11 (shielded identity create) → Common, ✅ in-UI ([#3913](https://github.com/dashpay/platform/issues/3913)) +* **swift-example-app:** remove CORE-11/12/13 (not-implemented Core actions) from test plan ([#3919](https://github.com/dashpay/platform/issues/3919)) +* **swift-example-app:** remove TOK-17 (calculate token ID utility) from test plan ([#3925](https://github.com/dashpay/platform/issues/3925)) +* **swift-example-app:** retire GRP-04 from the QA catalog ([#3932](https://github.com/dashpay/platform/issues/3932)) +* **swift-example-app:** retire stub builder rows VOTE-07/ID-13 ([#3929](https://github.com/dashpay/platform/issues/3929)) + + +### Tests + +* **drive-abci:** fix direct-selling tests broken by empty-schedule validation ([#3876](https://github.com/dashpay/platform/issues/3876)) +* **swift-example-app:** cover KeyDisableGate and correct consensus-framing comments ([#3920](https://github.com/dashpay/platform/issues/3920)) +* **swift-sdk:** move swift-sdk unit test defined in the example app to the swift-sdk unit tests suite ([#3917](https://github.com/dashpay/platform/issues/3917)) +* **wasm-sdk:** raise withdrawal test amount to the v12 minimum ([#3867](https://github.com/dashpay/platform/issues/3867)) + + +### Code Refactoring + +* **sdk:** per-network protocol-version floor + version_pinned unification ([#3900](https://github.com/dashpay/platform/issues/3900)) + + +### Build System + +* **dashmate:** update Tenderdash image to v1.6.0 ([#3940](https://github.com/dashpay/platform/issues/3940)) +* update grovedb dependency from git revision to v5.0.0 tag ([#3971](https://github.com/dashpay/platform/issues/3971)) +* update rust-dashcore to v0.44.0 ([#3973](https://github.com/dashpay/platform/issues/3973)) + + +### Miscellaneous Chores + +* bump rust-dashcore to rev without Address::network() method ([#3788](https://github.com/dashpay/platform/issues/3788)) +* retarget in-repo branch references from v3.1-dev to v4.0-dev ([#3972](https://github.com/dashpay/platform/issues/3972)) + ## [4.0.0-rc.2](https://github.com/dashpay/platform/compare/v4.0.0-rc.1...v4.0.0-rc.2) (2026-06-12) diff --git a/Cargo.lock b/Cargo.lock index 1ca6768db2..5148cee60c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "check-features" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "toml 0.8.23", ] @@ -1528,7 +1528,7 @@ dependencies = [ [[package]] name = "dapi-grpc" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "dash-platform-macros", "futures-core", @@ -1615,7 +1615,7 @@ dependencies = [ [[package]] name = "dash-async" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "thiserror 2.0.18", "tokio", @@ -1624,7 +1624,7 @@ dependencies = [ [[package]] name = "dash-context-provider" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "dash-async", "dpp", @@ -1655,7 +1655,7 @@ dependencies = [ [[package]] name = "dash-platform-balance-checker" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "anyhow", "clap", @@ -1670,7 +1670,7 @@ dependencies = [ [[package]] name = "dash-platform-macros" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "heck 0.5.0", "quote", @@ -1679,7 +1679,7 @@ dependencies = [ [[package]] name = "dash-sdk" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "arc-swap", "assert_matches", @@ -1823,7 +1823,7 @@ dependencies = [ [[package]] name = "dashpay-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "platform-value", "platform-version", @@ -1833,7 +1833,7 @@ dependencies = [ [[package]] name = "data-contracts" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "dashpay-contract", "dpns-contract", @@ -2046,7 +2046,7 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dpns-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "platform-value", "platform-version", @@ -2056,7 +2056,7 @@ dependencies = [ [[package]] name = "dpp" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "anyhow", "assert_matches", @@ -2114,7 +2114,7 @@ dependencies = [ [[package]] name = "dpp-json-convertible-derive" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "proc-macro2", "quote", @@ -2123,7 +2123,7 @@ dependencies = [ [[package]] name = "drive" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "arc-swap", "assert_matches", @@ -2164,7 +2164,7 @@ dependencies = [ [[package]] name = "drive-abci" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "arc-swap", "assert_matches", @@ -2225,7 +2225,7 @@ dependencies = [ [[package]] name = "drive-proof-verifier" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "bincode", "dapi-grpc", @@ -3960,7 +3960,7 @@ dependencies = [ [[package]] name = "json-schema-compatibility-validator" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "assert_matches", "json-patch", @@ -4103,7 +4103,7 @@ dependencies = [ [[package]] name = "keyword-search-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "base58", "platform-value", @@ -4292,7 +4292,7 @@ dependencies = [ [[package]] name = "masternode-reward-shares-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "platform-value", "platform-version", @@ -5060,7 +5060,7 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "platform-encryption" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "aes", "cbc", @@ -5071,7 +5071,7 @@ dependencies = [ [[package]] name = "platform-serialization" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "bincode", "platform-version", @@ -5079,7 +5079,7 @@ dependencies = [ [[package]] name = "platform-serialization-derive" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "proc-macro2", "quote", @@ -5089,7 +5089,7 @@ dependencies = [ [[package]] name = "platform-value" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "base64 0.22.1", "bincode", @@ -5108,7 +5108,7 @@ dependencies = [ [[package]] name = "platform-value-convertible" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "quote", "syn 2.0.117", @@ -5116,7 +5116,7 @@ dependencies = [ [[package]] name = "platform-version" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "bincode", "grovedb-version", @@ -5126,7 +5126,7 @@ dependencies = [ [[package]] name = "platform-versioning" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "proc-macro2", "quote", @@ -5135,7 +5135,7 @@ dependencies = [ [[package]] name = "platform-wallet" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "arc-swap", "async-trait", @@ -5172,7 +5172,7 @@ dependencies = [ [[package]] name = "platform-wallet-ffi" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "anyhow", "bincode", @@ -5200,7 +5200,7 @@ dependencies = [ [[package]] name = "platform-wallet-storage" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "apple-native-keyring-store", "argon2", @@ -6215,7 +6215,7 @@ dependencies = [ [[package]] name = "rs-dapi" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "async-trait", "axum 0.8.9", @@ -6264,7 +6264,7 @@ dependencies = [ [[package]] name = "rs-dapi-client" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "backon", "chrono", @@ -6289,7 +6289,7 @@ dependencies = [ [[package]] name = "rs-dash-event-bus" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "metrics", "tokio", @@ -6321,7 +6321,7 @@ dependencies = [ [[package]] name = "rs-sdk-ffi" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "async-trait", "bincode", @@ -6355,7 +6355,7 @@ dependencies = [ [[package]] name = "rs-sdk-trusted-context-provider" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "arc-swap", "dash-async", @@ -6374,7 +6374,7 @@ dependencies = [ [[package]] name = "rs-unified-sdk-ffi" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "dash-network", "key-wallet-ffi", @@ -7114,7 +7114,7 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simple-signer" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "async-trait", "base64 0.22.1", @@ -7250,7 +7250,7 @@ dependencies = [ [[package]] name = "strategy-tests" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "bincode", "dpp", @@ -7641,7 +7641,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token-history-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "platform-value", "platform-version", @@ -8489,7 +8489,7 @@ dependencies = [ [[package]] name = "wallet-utils-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "platform-value", "platform-version", @@ -8632,7 +8632,7 @@ checksum = "a8145dd1593bf0fb137dbfa85b8be79ec560a447298955877804640e40c2d6ea" [[package]] name = "wasm-dpp" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "anyhow", "async-trait", @@ -8656,7 +8656,7 @@ dependencies = [ [[package]] name = "wasm-dpp2" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "anyhow", "async-trait", @@ -8675,7 +8675,7 @@ dependencies = [ [[package]] name = "wasm-drive-verify" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "base64 0.22.1", "bincode", @@ -8730,7 +8730,7 @@ dependencies = [ [[package]] name = "wasm-sdk" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "base64 0.22.1", "bip39", @@ -9173,7 +9173,7 @@ dependencies = [ [[package]] name = "withdrawals-contract" -version = "4.0.0-rc.2" +version = "4.0.0" dependencies = [ "num_enum 0.5.11", "platform-value", diff --git a/Cargo.toml b/Cargo.toml index 6d462f6275..c7703f6b68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,5 +110,5 @@ opt-level = 3 [workspace.package] -version = "4.0.0-rc.2" +version = "4.0.0" rust-version = "1.92" diff --git a/package.json b/package.json index 3a8022e57b..cee417710c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/platform", - "version": "4.0.0-rc.2", + "version": "4.0.0", "private": true, "scripts": { "setup": "yarn install && yarn run build && yarn run configure", diff --git a/packages/bench-suite/package.json b/packages/bench-suite/package.json index 53531959c9..c882593e1d 100644 --- a/packages/bench-suite/package.json +++ b/packages/bench-suite/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/bench-suite", "private": true, - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Dash Platform benchmark tool", "scripts": { "bench": "node ./bin/bench.js", diff --git a/packages/dapi-grpc/package.json b/packages/dapi-grpc/package.json index 05ad80706c..6c2ca4fed4 100644 --- a/packages/dapi-grpc/package.json +++ b/packages/dapi-grpc/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dapi-grpc", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "DAPI GRPC definition file and generated clients", "browser": "browser.js", "main": "node.js", diff --git a/packages/dapi/package.json b/packages/dapi/package.json index d83f85f294..3b1f6935d6 100644 --- a/packages/dapi/package.json +++ b/packages/dapi/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/dapi", "private": true, - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "A decentralized API for the Dash network", "scripts": { "api": "node scripts/api.js", diff --git a/packages/dash-spv/package.json b/packages/dash-spv/package.json index 16d4e29575..e331237c12 100644 --- a/packages/dash-spv/package.json +++ b/packages/dash-spv/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dash-spv", - "version": "5.0.0-rc.2", + "version": "5.0.0", "description": "Repository containing SPV functions used by @dashevo", "main": "index.js", "scripts": { diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index bde04e242c..97994c3b75 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -1546,6 +1546,21 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return configFile; }, + '4.0.0': (configFile) => { + Object.entries(configFile.configs) + .forEach(([, options]) => { + // The drive and rs-dapi image tags are derived from the package + // major version. Re-pin them from the base config so operators + // upgrading from a prerelease of this major, or from an older + // major, move off their stale tag onto the current stable images. + // The legacy 0.25.x migrations already do this, but only fire for + // configs old enough to cross them; recent upgraders need it here. + options.platform.drive.abci.docker.image = base.get('platform.drive.abci.docker.image'); + options.platform.dapi.rsDapi.docker.image = base.get('platform.dapi.rsDapi.docker.image'); + }); + + return configFile; + }, }; } diff --git a/packages/dashmate/package.json b/packages/dashmate/package.json index b5b477336a..c598737b0b 100644 --- a/packages/dashmate/package.json +++ b/packages/dashmate/package.json @@ -1,6 +1,6 @@ { "name": "dashmate", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Distribution package for Dash node installation", "scripts": { "lint": "eslint .", diff --git a/packages/dashmate/test/unit/config/configFile/migrateConfigFileFactory.spec.js b/packages/dashmate/test/unit/config/configFile/migrateConfigFileFactory.spec.js index eb7efe51ae..26dfb0590f 100644 --- a/packages/dashmate/test/unit/config/configFile/migrateConfigFileFactory.spec.js +++ b/packages/dashmate/test/unit/config/configFile/migrateConfigFileFactory.spec.js @@ -45,4 +45,44 @@ describe('migrateConfigFileFactory', () => { expect(migratedConfigFileData).to.be.deep.equal(currentConfigFileData); }); + + it('should refresh the version-derived platform images when upgrading from a recent version', async () => { + // The drive and rs-dapi image tags are derived from the package major + // version. An operator upgrading from a recent version (e.g. a prerelease + // of the same major) sits past the legacy 0.25.x migrations that refresh + // images from the base config, so a per-release migration must re-pin them + // or they stay stuck on the old/prerelease tag. + const { version } = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT_DIR, 'package.json'), 'utf8')); + + const defaultConfigFileData = createConfigFile().toObject(); + const [firstConfigName] = Object.keys(defaultConfigFileData.configs); + const expectedDriveImage = defaultConfigFileData + .configs[firstConfigName].platform.drive.abci.docker.image; + const expectedRsDapiImage = defaultConfigFileData + .configs[firstConfigName].platform.dapi.rsDapi.docker.image; + + const staleConfigFileData = createConfigFile().toObject(); + staleConfigFileData.configFormatVersion = '4.0.0-rc.2'; + for (const options of Object.values(staleConfigFileData.configs)) { + options.platform.drive.abci.docker.image = 'dashpay/drive:4-rc'; + options.platform.dapi.rsDapi.docker.image = 'dashpay/rs-dapi:4-rc'; + } + + const migratedConfigFileData = migrateConfigFile( + staleConfigFileData, + staleConfigFileData.configFormatVersion, + version, + ); + + for (const [name, options] of Object.entries(migratedConfigFileData.configs)) { + expect(options.platform.drive.abci.docker.image).to.equal( + expectedDriveImage, + `drive image not refreshed for ${name}`, + ); + expect(options.platform.dapi.rsDapi.docker.image).to.equal( + expectedRsDapiImage, + `rs-dapi image not refreshed for ${name}`, + ); + } + }); }); diff --git a/packages/dashpay-contract/package.json b/packages/dashpay-contract/package.json index a7a1762c53..7d867fb30c 100644 --- a/packages/dashpay-contract/package.json +++ b/packages/dashpay-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dashpay-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Reference contract of the DashPay DPA on Dash Evolution", "scripts": { "lint": "eslint .", diff --git a/packages/dpns-contract/package.json b/packages/dpns-contract/package.json index 308b483ba5..cd497932f9 100644 --- a/packages/dpns-contract/package.json +++ b/packages/dpns-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dpns-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "A contract and helper scripts for DPNS DApp", "scripts": { "lint": "eslint .", diff --git a/packages/js-dapi-client/package.json b/packages/js-dapi-client/package.json index 065a03e0b5..72eadfb5a3 100644 --- a/packages/js-dapi-client/package.json +++ b/packages/js-dapi-client/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dapi-client", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Client library used to access Dash DAPI endpoints", "main": "lib/index.js", "contributors": [ diff --git a/packages/js-dash-sdk/package.json b/packages/js-dash-sdk/package.json index bb7789da58..65ce37ded9 100644 --- a/packages/js-dash-sdk/package.json +++ b/packages/js-dash-sdk/package.json @@ -1,6 +1,6 @@ { "name": "dash", - "version": "7.0.0-rc.2", + "version": "7.0.0", "description": "Dash library for JavaScript/TypeScript ecosystem (Wallet, DAPI, Primitives, BLS, ...)", "main": "build/index.js", "unpkg": "dist/dash.min.js", diff --git a/packages/js-evo-sdk/package.json b/packages/js-evo-sdk/package.json index c6bb264580..2e6b17588c 100644 --- a/packages/js-evo-sdk/package.json +++ b/packages/js-evo-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/evo-sdk", - "version": "4.0.0-rc.2", + "version": "4.0.0", "type": "module", "main": "./dist/evo-sdk.module.js", "types": "./dist/sdk.d.ts", diff --git a/packages/js-grpc-common/package.json b/packages/js-grpc-common/package.json index 568edad768..6c565660c0 100644 --- a/packages/js-grpc-common/package.json +++ b/packages/js-grpc-common/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/grpc-common", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Common GRPC library", "main": "index.js", "scripts": { diff --git a/packages/keyword-search-contract/package.json b/packages/keyword-search-contract/package.json index 319108e87c..44557d5b32 100644 --- a/packages/keyword-search-contract/package.json +++ b/packages/keyword-search-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/keyword-search-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "A contract that allows searching for contracts", "scripts": { "lint": "eslint .", diff --git a/packages/masternode-reward-shares-contract/package.json b/packages/masternode-reward-shares-contract/package.json index 1d7e3f38b1..c27273e10b 100644 --- a/packages/masternode-reward-shares-contract/package.json +++ b/packages/masternode-reward-shares-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/masternode-reward-shares-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "A contract and helper scripts for reward sharing", "scripts": { "lint": "eslint .", diff --git a/packages/platform-test-suite/package.json b/packages/platform-test-suite/package.json index 031f0d4044..e0e615a07a 100644 --- a/packages/platform-test-suite/package.json +++ b/packages/platform-test-suite/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/platform-test-suite", "private": true, - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Dash Network end-to-end tests", "scripts": { "test": "yarn exec bin/test.sh", diff --git a/packages/token-history-contract/package.json b/packages/token-history-contract/package.json index 9cb96f2d72..0209c66af8 100644 --- a/packages/token-history-contract/package.json +++ b/packages/token-history-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/token-history-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "The token history contract", "scripts": { "lint": "eslint .", diff --git a/packages/wallet-lib/package.json b/packages/wallet-lib/package.json index f962e4f86f..520600c74f 100644 --- a/packages/wallet-lib/package.json +++ b/packages/wallet-lib/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wallet-lib", - "version": "11.0.0-rc.2", + "version": "11.0.0", "description": "Light wallet library for Dash", "main": "src/index.js", "unpkg": "dist/wallet-lib.min.js", diff --git a/packages/wallet-utils-contract/package.json b/packages/wallet-utils-contract/package.json index 9d8a65b781..1320129e60 100644 --- a/packages/wallet-utils-contract/package.json +++ b/packages/wallet-utils-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wallet-utils-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "A contract and helper scripts for Wallet DApp", "scripts": { "lint": "eslint .", diff --git a/packages/wasm-dpp/package.json b/packages/wasm-dpp/package.json index 63e020cb43..b918ac8255 100644 --- a/packages/wasm-dpp/package.json +++ b/packages/wasm-dpp/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wasm-dpp", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "The JavaScript implementation of the Dash Platform Protocol", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/wasm-dpp2/package.json b/packages/wasm-dpp2/package.json index de14756131..f427357ec9 100644 --- a/packages/wasm-dpp2/package.json +++ b/packages/wasm-dpp2/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wasm-dpp2", - "version": "4.0.0-rc.2", + "version": "4.0.0", "type": "module", "main": "./dist/dpp.js", "types": "./dist/dpp.d.ts", diff --git a/packages/wasm-drive-verify/package.json b/packages/wasm-drive-verify/package.json index 54b0645a1f..8eacdeeb2a 100644 --- a/packages/wasm-drive-verify/package.json +++ b/packages/wasm-drive-verify/package.json @@ -3,7 +3,7 @@ "collaborators": [ "Dash Core Group " ], - "version": "4.0.0-rc.2", + "version": "4.0.0", "license": "MIT", "description": "WASM bindings for Drive verify functions", "repository": { diff --git a/packages/wasm-sdk/package.json b/packages/wasm-sdk/package.json index 847e5e0e52..f1fa4f76e9 100644 --- a/packages/wasm-sdk/package.json +++ b/packages/wasm-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wasm-sdk", - "version": "4.0.0-rc.2", + "version": "4.0.0", "type": "module", "main": "./dist/sdk.js", "types": "./dist/sdk.d.ts", diff --git a/packages/withdrawals-contract/package.json b/packages/withdrawals-contract/package.json index 9d6113ab26..9da2829634 100644 --- a/packages/withdrawals-contract/package.json +++ b/packages/withdrawals-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/withdrawals-contract", - "version": "4.0.0-rc.2", + "version": "4.0.0", "description": "Data Contract to manipulate and track withdrawals", "scripts": { "build": "",