diff --git a/CLAUDE.md b/CLAUDE.md index 9760866d1..9f614f5ce 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,7 +89,7 @@ The DAPI endpoint reference is split between an overview page (`docs/reference/d When you add or materially update an entry on a detail page, also update the matching row on `dapi-endpoints.md`: - Keep the description in sync between the two pages. -- Prefix the overview row's description with `**Added in Dash Platform vX.Y.Z**` (new endpoints) or `**Updated in Dash Platform vX.Y.Z**` (modified endpoints), followed by `
` and the description. Use **bold** for the current release's annotations; older releases use *italics*. +- Prefix the overview row's description with `**Added in Dash Platform vX.Y.Z**` (new endpoints) or `**Updated in Dash Platform vX.Y.Z**` (modified endpoints), followed by `
` and the description. Use **bold** for the current major release's annotations; older major releases use *italics*. - For a whole new endpoint group, wrap the new section in a `:::{versionadded} X.Y.Z` admonition above its table — see Security Groups, Tokens, Address System, and Shielded Transactions for the pattern. For the full per-release endpoint review process (proto diff, example refresh, demoting annotations to italics), see [RELEASE.md](RELEASE.md). diff --git a/_static/dashmint-lite.html b/_static/dashmint-lite.html index 084c924ed..841166c65 100644 --- a/_static/dashmint-lite.html +++ b/_static/dashmint-lite.html @@ -119,7 +119,7 @@

Browse cards

// package and serves it as a browser-native ES module. Pinned to the same // version the React app at ../package.json depends on so both UIs behave // identically against the same testnet contract. - import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.0.0'; + import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.1.0'; // The token-enabled "card" data contract is already published on testnet by // the React app. Anyone querying with the same contract id hits the same @@ -131,12 +131,11 @@

Browse cards

// nodes — no node URL or config needed. connect() does the gRPC handshake // + initial sync. No identity or signing is required for read-only queries. // - // Workaround: pin the platform protocol version for evo-sdk dev.6 so the - // SDK doesn't ask testnet for a newer protocol it can't decode. Mirrors - // PLATFORM_VERSION_OVERRIDE in setupDashClient-core.mjs. Remove once a - // fixed SDK release lands. + // The platform protocol version is left unset on purpose: the SDK negotiates + // it with the network. Passing `version` pins it and disables that, so a + // hardcoded value silently goes stale at the next network upgrade. async function connectSdk() { - const sdk = EvoSDK.testnetTrusted({ version: 11 }); + const sdk = EvoSDK.testnetTrusted(); await sdk.connect(); return sdk; } diff --git a/_static/dashnote-lite.html b/_static/dashnote-lite.html index 809a7f867..e1241e054 100644 --- a/_static/dashnote-lite.html +++ b/_static/dashnote-lite.html @@ -129,7 +129,7 @@

Get note by ID

// package and serves it as a browser-native ES module. Pinned to the same // version the React app at ../package.json depends on so both UIs behave // identically against the same testnet contract. - import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.0.0'; + import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.1.0'; // The "note" data contract is already published on testnet by the React app. // Anyone querying with the same contract id hits the same documents. diff --git a/_static/dashproof-lite.html b/_static/dashproof-lite.html index dfa6ae06f..8898daed1 100644 --- a/_static/dashproof-lite.html +++ b/_static/dashproof-lite.html @@ -120,7 +120,7 @@

History by chainId

// package and serves it as a browser-native ES module. Pinned to the same // version the React app at ../package.json depends on so both UIs behave // identically against the same testnet contract. - import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.0.0'; + import { EvoSDK } from 'https://esm.sh/@dashevo/evo-sdk@4.1.0'; // The "anchor" data contract is already published on testnet by the React app. // Anyone querying with the same contract id hits the same documents. diff --git a/docs/explanations/dapi.md b/docs/explanations/dapi.md index b5cc9eeac..9c50e1cfe 100644 --- a/docs/explanations/dapi.md +++ b/docs/explanations/dapi.md @@ -31,4 +31,4 @@ retrieval. ## Endpoint Overview -DAPI currently provides 2 types of endpoints: [JSON-RPC](https://www.jsonrpc.org/) and [gRPC](https://grpc.io/docs/guides/). The JSON-RPC endpoints expose some layer 1 information while the gRPC endpoints support layer 2 as well as streaming of events related to blocks, transactions/transitions, and masternode-list updates. For a list of all endpoints and usage details, please see the [DAPI endpoint reference section](../reference/dapi-endpoints.md). +DAPI currently provides 2 types of endpoints: [JSON-RPC](https://www.jsonrpc.org/) and [gRPC](https://grpc.io/docs/guides/). The JSON-RPC endpoints expose some layer 1 information while the gRPC endpoints support layer 2. The layer 1 Core gRPC service additionally provides streaming of events related to blocks, transactions, and masternode-list updates; the layer 2 Platform endpoints are request/response only. For a list of all endpoints and usage details, please see the [DAPI endpoint reference section](../reference/dapi-endpoints.md). diff --git a/docs/explanations/dpns.md b/docs/explanations/dpns.md index f64bbc886..ea247c9cc 100644 --- a/docs/explanations/dpns.md +++ b/docs/explanations/dpns.md @@ -42,8 +42,8 @@ Since some names may be popular, the registration process includes a voting mech :::{note} This process only applies to valid names that meet the following conditions: -* Less than 20 characters long (i.e. "alice", "quantumexplorer") AND -* Contain no numbers or only contain the number(s) 0 and/or 1 (i.e. "bob", "carol01") +* Between 3 and 19 characters long (i.e. "alice", "quantumexplorer") AND +* Contain no numbers other than 0 and/or 1, and no characters besides letters and hyphens (i.e. "bob", "carol01", "quantum-explorer") All other available names can be registered immediately. ::: @@ -70,14 +70,20 @@ Assuming masternodes do not vote to lock, the identity receiving the most votes Locked names cannot currently be re-requested or awarded. This policy may be revisited in future Platform releases. ::: +### Name transfers and sales + +Registering a name is not necessarily the end of its lifecycle. A registered name can be transferred to another identity or offered for sale and bought by another identity. The DPNS contract has always declared names transferable and available for direct purchase, but Platform's validation rules rejected those operations until protocol version 13 (introduced in Dash Platform v4.1) lifted the restriction. Once ownership changes, the name resolves to its new owner, and that identity's private keys are what prove ownership from then on. + +The name record itself remains immutable and permanent: it cannot be edited or deleted, only transferred or sold. A name's transfer, purchase, and listing history is recorded, so the chain of ownership and the prices it was offered at can be retrieved and verified. + ### Implementation -DPNS names have several constraints as defined in the [DPNS data contract](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json). The constraints provide compatibility with DNS and protection from homograph attacks: +DPNS names have several constraints as defined in the [DPNS data contract](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json). The constraints provide compatibility with DNS and protection from homograph attacks: 1. Minimum length - 3 characters 1. Maximum length - 63 characters 1. Usable characters - `0-9`, `-` (hyphen), `a-z`, and `A-Z` (case sensitive) - * Note: Use of `-` as a prefix/suffix to a name is _not_ allowed (e.g. `-name` or `name-`). This constraint is defined by this JSON-Schema [pattern](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json#L44) in the DPNS data contract: `"^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$"` + * Note: Use of `-` as a prefix/suffix to a name is _not_ allowed (e.g. `-name` or `name-`). This constraint is defined by this JSON-Schema [pattern](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json#L47) in the DPNS data contract: `"^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$"` 1. Domain labels are converted to lowercase for case-insensitive uniqueness validation. 1. To mitigate [homograph attacks](https://en.wikipedia.org/wiki/IDN_homograph_attack), `o` is replaced with `0` and `i`/`l` are replaced with `1`. For example, "Alice" is normalized to "a11ce". diff --git a/docs/explanations/drive-platform-chain.md b/docs/explanations/drive-platform-chain.md index b81b00d1d..50b698db1 100644 --- a/docs/explanations/drive-platform-chain.md +++ b/docs/explanations/drive-platform-chain.md @@ -6,7 +6,7 @@ ## Overview -The platform chain is the [Drive](../explanations/drive.md) component responsible for replicating the platform state across all masternodes participating in the network. Masternodes operate this Proof of Service (PoSe) chain to provide layer 2 consensus and support Dash Platform-specific requirements without impacting layer 1 functionality. Although the platform chain can read from the Dash layer 1 core blockchain, the core blockchain is not dependent on it or aware of it. +The platform chain is the [Drive](../explanations/drive.md) component responsible for replicating the platform state across all evonodes participating in the network. Evonodes (the high-performance masternode tier) operate this Proof of Service (PoSe) chain to provide layer 2 consensus and support Dash Platform-specific requirements without impacting layer 1 functionality. Although the platform chain can read from the Dash layer 1 core blockchain, the core blockchain is not dependent on it or aware of it. ## Details @@ -19,7 +19,7 @@ Early designs of Drive were based on using on the layer 1 core blockchain and [I In order to support Dash Platform's performance requirements, the platform chain has the following design characteristics: - Relies on masternode Proof of Service, not miner Proof of Work (PoW) -- Hosted exclusively on masternodes +- Hosted exclusively on evonodes (the high-performance masternode tier) - Uses a [practical Byzantine Fault Tolerance (pBFT)](../reference/glossary.md#practical-byzantine-fault-tolerance-pbft) consensus algorithm - Has a deterministic fee structure - Provides fast (~5 second target block spacing) and absolute block finality (no reorgs) diff --git a/docs/explanations/drive.md b/docs/explanations/drive.md index f4dadeebe..27a0168ee 100644 --- a/docs/explanations/drive.md +++ b/docs/explanations/drive.md @@ -6,7 +6,7 @@ ## Overview -Using the traditional, layer 1 blockchain for data storage is widely known to be expensive and inefficient. Consequently, data for Dash Platform applications is stored in Drive, a layer 2 component that provides decentralized storage hosted by masternodes. As data changes over time, Drive maintains a record of the current state of each item to support easy retrieval using [DAPI](../explanations/dapi.md). +Using the traditional, layer 1 blockchain for data storage is widely known to be expensive and inefficient. Consequently, data for Dash Platform applications is stored in Drive, a layer 2 component that provides decentralized storage hosted by evonodes. As data changes over time, Drive maintains a record of the current state of each item to support easy retrieval using [DAPI](../explanations/dapi.md). ## Details diff --git a/docs/explanations/fees.md b/docs/explanations/fees.md index 7987584cb..19373223a 100644 --- a/docs/explanations/fees.md +++ b/docs/explanations/fees.md @@ -42,13 +42,13 @@ Refer to the [Identity explanation](../explanations/identity.md) section for inf ## Fee Multiplier -Given fluctuations of the Dash price, a variable *Fee Multiplier* provides a way to balance the cost of fees with network hosting requirements. All fees are multiplied by the Fee Multiplier: +The *Fee Multiplier* provides a mechanism to balance the cost of fees against network hosting requirements as the Dash price fluctuates. It is recorded per epoch and used when distributing collected fees from the credit pools, along with epoch accounting. -```text - feePaid = initialFee * feeMultiplier -``` +The multiplier does not scale the fee a user is charged. The active fee version fixes it at 1.0x, +and the final fee charged for a state transition is calculated using the complete formula below, +including any user fee increase and storage refund. -The Fee Multiplier is subject to change at any time via network governance and protocol updates. +Fee parameters, including the multiplier, are fixed by the active fee version. They change only when the network activates a new protocol version, which happens once enough evonodes signal the newer version and the threshold is met at an epoch change. \n" - } - [/block] + Response shape: { "fee": } ``` ## Deprecated Endpoints @@ -839,7 +878,10 @@ The following endpoints were recently deprecated. See the [previous version of d ### getStatus :::{attention} -Deprecated in Dash Platform v1.0.0 +Deprecated in Dash Platform v1.0.0. Replaced by [`getBlockchainStatus`](#getblockchainstatus) and +[`getMasternodeStatus`](#getmasternodestatus). This is distinct from the Platform +[`getStatus`](../reference/dapi-endpoints-platform-endpoints.md#getstatus) endpoint, which remains +available. ::: **Returns**: Status information from the Core chain @@ -990,5 +1032,5 @@ Note: The gRPCurl response `bestBlockHash`, `chainWork`, and `proTxHash` data is Implementation details related to the information on this page can be found in: -- The [Platform repository](https://github.com/dashpay/platform/tree/master/packages/dapi) `packages/dapi/lib/grpcServer/handlers/core` folder +- The [Platform repository](https://github.com/dashpay/platform/tree/master/packages/rs-dapi/src/services) `packages/rs-dapi/src/services` folder, which contains the DAPI implementation deployed by dashmate - The [Platform repository](https://github.com/dashpay/platform/tree/master/packages/dapi-grpc) `packages/dapi-grpc/protos/core` folder diff --git a/docs/reference/dapi-endpoints-grpc-overview.md b/docs/reference/dapi-endpoints-grpc-overview.md index 5ad55f548..f1fdd6b2c 100644 --- a/docs/reference/dapi-endpoints-grpc-overview.md +++ b/docs/reference/dapi-endpoints-grpc-overview.md @@ -35,3 +35,18 @@ The [gRPC UI](https://github.com/fullstorydev/grpcui) tool provides a way to int # Use Core gRPC grpcui -insecure -open-browser -proto protos/core/v0/core.proto seed-1.testnet.networks.dash.org:1443 ``` + +## Stream termination and backpressure + +:::{versionadded} 4.1.0 +::: + +Streaming endpoints apply per-stream delivery bounds, so a stream that has already been established can be terminated by the server with `RESOURCE_EXHAUSTED`. This happens when: + +- The client cannot keep up with delivery and the stream's pending-event or pending-byte budget is exceeded. +- The initial mempool snapshot exceeds the per-stream transaction count or byte budget. See + [`subscribeToTransactionsWithProofs`](dapi-endpoints-core-grpc-endpoints.md#subscribetotransactionswithproofs) + for endpoint-specific recovery guidance. +- The handover from replaying historical data to live delivery does not complete within 180 seconds. + +Treat this status as a resumable backpressure signal rather than a fatal error. For confirmed block data, reconnect and resume from the last block your client finished processing. A `RESOURCE_EXHAUSTED` returned when *opening* a stream means the node's concurrent-stream limit for that endpoint is reached — back off and retry, or connect to a different node. diff --git a/docs/reference/dapi-endpoints-json-rpc-endpoints.md b/docs/reference/dapi-endpoints-json-rpc-endpoints.md index 53095b021..f794b6290 100644 --- a/docs/reference/dapi-endpoints-json-rpc-endpoints.md +++ b/docs/reference/dapi-endpoints-json-rpc-endpoints.md @@ -222,6 +222,64 @@ puts response.read_body } ``` +### getStatus + +**Returns**: Platform status information. This is the JSON-RPC equivalent of the Platform +[`getStatus`](../reference/dapi-endpoints-platform-endpoints.md#getstatus) gRPC endpoint, and returns +the same response object. + +**Parameters**: none + +#### Example Request and Response + +::::{tab-set} +:::{tab-item} Curl +:sync: curl +```shell +curl -k --request POST \ + --url https://seed-1.testnet.networks.dash.org:1443/ \ + --header 'content-type: application/json' \ + --data '{ + "method":"getStatus", + "id":1, + "jsonrpc":"2.0", + "params":{} + }' +``` +::: +:::: + +### sendRawTransaction + +**Returns**: the transaction id (TXID) of the submitted transaction + +**Parameters**: + +| Name | Type | Required | Description | +| ---------------- | ------- | -------- | ------------------------------------------------------------------ | +| `transaction` | String | Yes | The raw transaction, hex-encoded | +| `allowHighFees` | Boolean | No | Set to `true` to bypass the high-fee rejection check (default: `false`) | +| `bypassLimits` | Boolean | No | Set to `true` to bypass mempool rate limits (default: `false`) | + +#### Example Request and Response + +::::{tab-set} +:::{tab-item} Curl +:sync: curl +```shell +curl -k --request POST \ + --url https://seed-1.testnet.networks.dash.org:1443/ \ + --header 'content-type: application/json' \ + --data '{ + "method":"sendRawTransaction", + "id":1, + "jsonrpc":"2.0", + "params": ["03000000019a2b1b2b...", false, false] + }' +``` +::: +:::: + ## Deprecated Endpoints The following endpoints were recently deprecated. See the [previous version of this @@ -368,4 +426,4 @@ puts response.read_body Implementation details related to the information on this page can be found in: -- The [DAPI repository](https://github.com/dashpay/platform/tree/master/packages/dapi) `lib/rpcServer/commands` folder \ No newline at end of file +- The [rs-dapi package](https://github.com/dashpay/platform/tree/master/packages/rs-dapi) `src/protocol/jsonrpc_translator` module diff --git a/docs/reference/dapi-endpoints-platform-endpoints.md b/docs/reference/dapi-endpoints-platform-endpoints.md index c16dc8d20..d27c15d6a 100644 --- a/docs/reference/dapi-endpoints-platform-endpoints.md +++ b/docs/reference/dapi-endpoints-platform-endpoints.md @@ -13,6 +13,36 @@ Please refer to the [gRPC Overview](../reference/dapi-endpoints-grpc-overview.md All Dash Platform endpoints are versioned so future updates can be done without creating significant issues for API consumers. +### Request size limit + +:::{versionadded} 4.1.0 +Platform gRPC requests are capped at 128 KiB encoded, reduced from 64 MiB. A larger request is rejected by the transport before it reaches the endpoint. The limit sits above every per-endpoint budget — the largest are [`getPathElements`](#getpathelements) at 64 KiB of path and key components and [`broadcastStateTransition`](#broadcaststatetransition) at 20 KiB — so requests within those bounds are unaffected. +::: + +### Result limits and pagination + +Endpoints that return a list accept a `count` or `limit` field. Unless an endpoint states otherwise, +the default and maximum are 100, although node operators may configure a different limit. A value of +`0` or a value above the node's limit is rejected. Exceptions are documented in the relevant +endpoint sections. + +Endpoints that accept an array of identifiers (for example identity IDs, token IDs, or ProTx hashes) +accept at most 100 entries. + +A few endpoints accept a different range: + +| Endpoint | Accepted range | +| -------- | -------------- | +| [`getShieldedEncryptedNotes`](#getshieldedencryptednotes) | `count` is capped at 8,192 notes; `0` requests the maximum rather than being rejected | + +Some endpoints also cap the response independently of what the request asks for. These caps are +applied by the server and cannot be raised by the caller: + +| Endpoint | Response cap | +| -------- | ------------ | +| [`getRecentAddressBalanceChanges`](#getrecentaddressbalancechanges) | 100 blocks | +| [`getRecentCompactedAddressBalanceChanges`](#getrecentcompactedaddressbalancechanges) | 25 entries | + ### Data Proofs and Metadata Platform gRPC endpoints can provide [proofs](https://github.com/dashpay/platform/blob/master/packages/dapi-grpc/protos/platform/v0/platform.proto#L142-L149) so the data returned for a request can be verified as being valid. When requesting proofs, the data requested will be encoded as part of the proof in the response. Proofs are supported in the [js-evo-sdk](https://github.com/dashpay/platform/tree/master/packages/js-evo-sdk) and via the low-level [dapi-grpc library](https://github.com/dashpay/platform/tree/master/packages/dapi-grpc). @@ -36,30 +66,35 @@ Some [additional metadata](https://github.com/dashpay/platform/blob/master/packa [Masternode identities](../explanations/identity.md#masternode-identities) are created automatically by the system based on the [Core masternode registration transaction (protx) -hash](inv:user:std#ref-txs-proregtx). Masternode identity IDs are created by converting the protx -hash to base58. This can be done using an [online base58 +hash](inv:user:std#ref-txs-proregtx). The masternode *owner* identity ID is the protx hash itself, so +it is created by converting the protx hash to base58. This can be done using an [online base58 encoder](https://appdevtools.com/base58-encoder-decoder) or through JavaScript using the [bs58 package](https://www.npmjs.com/package/bs58) as shown below. For gRPCurl, convert the protx hash to base64 instead. This can be done using an [online hex to base64 encoder](https://base64.guru/converter/encode/hex). +The *voter* and *operator* identities use derived IDs instead: `SHA-256(protx_hash || voting_address)` +for the voter identity and `SHA-256(protx_hash || operator_public_key)` for the operator identity +([source](https://github.com/dashpay/platform/blob/v4.1.0/packages/rs-dpp/src/identifier/mod.rs#L5-L31)). +Encoding the protx hash alone will not produce a voter or operator identity ID. + ```{eval-rst} .. _reference-dapi-endpoints-platform-grpc-protx-to-id: ``` :::{code-block} javascript -:caption: Protx hash to identity ID +:caption: Protx hash to owner identity ID const bs58 = require('bs58').default; const protx = '8eca4bcbb3a124ab283afd42dad3bdb2077b3809659788a0f1daffce5b9f001f'; const base58Protx = bs58.encode(Buffer.from(protx, 'hex')); -console.log(`Masternode identity id (base58): ${base58Protx}`); +console.log(`Masternode owner identity id (base58): ${base58Protx}`); const base64Protx = Buffer.from(protx, 'hex').toString('base64'); -console.log(`Masternode identity id (base64): ${base64Protx}`); +console.log(`Masternode owner identity id (base64): ${base64Protx}`); // Output: -// Masternode identity id (base58): AcPogCxrxeas7jrWYG7TnLHKbsA5KLHGfvg6oYgANZ8J -// Masternode identity id (base64): jspLy7OhJKsoOv1C2tO9sgd7OAlll4ig8dr/zlufAB8= +// Masternode owner identity id (base58): AcPogCxrxeas7jrWYG7TnLHKbsA5KLHGfvg6oYgANZ8J +// Masternode owner identity id (base64): jspLy7OhJKsoOv1C2tO9sgd7OAlll4ig8dr/zlufAB8= ::: ## Contested Resource Endpoints @@ -74,6 +109,15 @@ DPNS names. The endpoints in this section allow clients to check the status of active contests, retrieve contestants, and obtain the outcome. +:::{versionadded} 4.1.0 +Serialized index and cursor values are now bounded. A request to `getContestedResources`, +`getContestedResourceVotersForIdentity`, or `getContestedResourceVoteState` is rejected with +`InvalidArgument` if it supplies more values than the contested index has properties, if any single +encoded value exceeds 4 KiB, if the combined encoded size of all index and cursor values in the +request exceeds 4 KiB, if a value nests arrays or maps more than 64 levels deep, or if a value has +trailing bytes after its encoding. Previously these values were decoded without bounds. +::: + ### getContestedResources Retrieves the contested resources for a specific contract, document type, and index. @@ -86,11 +130,11 @@ Retrieves the contested resources for a specific contract, document type, and in | ---------------------- | -------- | -------- | --------------------------------------------------------------------------- | | `contract_id` | Bytes | Yes | The ID of the data contract associated with the contested resources | | `document_type_name` | String | Yes | The name of the document type associated with the contested resources | -| `index_name` | String | Yes | The name of the index used to query the contested resources | +| `index_name` | String | Yes | The name of the document type's contested index. A document type has at most one contested index; naming any other index is rejected with `InvalidArgument` | | `start_index_values` | Array | No | Start values for index, for pagination | | `end_index_values` | Array | No | End values for index, for pagination | | `start_at_value_info` | Object | No | Start value information for pagination | -| `count` | Integer | No | Number of contested resources to return | +| `count` | Integer | No | Number of contested resources to return. See [Result limits and pagination](#result-limits-and-pagination) | | `order_ascending` | Boolean | No | Sort order for results | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested contested resources | @@ -151,7 +195,7 @@ Retrieves the voting record of a specific identity. | Name | Type | Required | Description | | ------------------------------ | -------- | -------- | ------------| | `identity_id` | Bytes | Yes | The ID of the identity whose votes are being requested | -| `limit` | Integer | No | Maximum number of results to return | +| `limit` | Integer | No | Maximum number of results to return. See [Result limits and pagination](#result-limits-and-pagination) | | `offset` | Integer | No | Offset for pagination | | `order_ascending` | Boolean | No | Sort order for results | | `start_at_vote_poll_id_info` | Object | No | Start poll ID information for pagination | @@ -265,6 +309,11 @@ grpcurl -proto protos/platform/v0/platform.proto \ ::: :::: +Each `voteChoice` carries a `voteChoiceType` of `TOWARDS_IDENTITY`, `ABSTAIN`, or `LOCK`. Because +`TOWARDS_IDENTITY` is the proto3 default it is omitted from JSON output, so the entries above are all +`TOWARDS_IDENTITY` votes. `identityId` is present only for `TOWARDS_IDENTITY`; abstain and lock votes +carry no `identityId`. + ### getContestedResourceVotersForIdentity Retrieves the voters for a specific identity associated with a contested resource. @@ -281,7 +330,7 @@ Retrieves the voters for a specific identity associated with a contested resourc | `index_values` | Array | Yes | The values used to query the contested resource | | `contestant_id` | Bytes | Yes | The ID of the identity for which to retrieve voters | | `start_at_identifier_info` | Object | No | Start identifier information for pagination | -| `count` | Integer | No | Number of results to return | +| `count` | Integer | No | Number of results to return. See [Result limits and pagination](#result-limits-and-pagination) | | `order_ascending` | Boolean | No | Sort order for results | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested voters | @@ -353,14 +402,34 @@ Retrieves the state of a vote for a specific contested resource. | ------------------------------------------------ | -------- | -------- | ------------------------------------------------------------------------------------------------------- | | `contract_id` | Bytes | Yes | The ID of the data contract associated with the contested resource | | `document_type_name` | String | Yes | The name of the document type associated with the contested resource | -| `index_name` | String | Yes | The name of the index used to query the contested resource | -| `index_values` | Array | Yes | The values used to query the contested resource. | +| `index_name` | String | Yes | The name of the document type's contested index. A document type has at most one contested index; naming any other index is rejected with `InvalidArgument` | +| `index_values` | Array | Yes | The values used to query the contested resource. Must contain exactly one value per contested index property. | | `result_type` | Enum | Yes | Specifies the result type to return: `DOCUMENTS`, `VOTE_TALLY`, or `DOCUMENTS_AND_VOTE_TALLY` | | `allow_include_locked_and`
`_abstaining_vote_tally` | Boolean | No | Include votes that are locked or abstaining in the tally | | `start_at_identifier_info` | Object | No | Start identifier information for pagination | -| `count` | Integer | No | Number of results to return | +| `count` | Integer | No | Number of results to return. See [Result limits and pagination](#result-limits-and-pagination) | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested vote state | +**Response Object** (`contestedResourceContenders`) + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `contenders` | Array | Contenders in the contest. Each has an `identifier`, an optional `voteCount`, and an optional serialized `document` | +| `abstainVoteTally` | Integer | Number of abstain votes. Returned only when `allow_include_locked_and_abstaining_vote_tally` is `true` | +| `lockVoteTally` | Integer | Number of lock votes. Returned only when `allow_include_locked_and_abstaining_vote_tally` is `true` | +| `finishedVoteInfo` | Object | Present only once the contest has concluded. See below | + +When the contest has finished, `finishedVoteInfo` contains: + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `finishedVoteOutcome` | Enum | `TOWARDS_IDENTITY`, `LOCKED`, or `NO_PREVIOUS_WINNER`. `TOWARDS_IDENTITY` is the proto3 default and is omitted from JSON output | +| `wonByIdentityId` | Bytes | The winning identity. Present only when the outcome is `TOWARDS_IDENTITY` | +| `finishedAtBlockHeight` | String (uint64) | Platform block height at which the contest concluded | +| `finishedAtCoreBlockHeight` | Integer | Core block height at which the contest concluded | +| `finishedAtBlockTimeMs` | String (uint64) | Block time in milliseconds at which the contest concluded | +| `finishedAtEpoch` | Integer | Epoch in which the contest concluded | + **Example Request and Response** ::::{tab-set} @@ -421,11 +490,18 @@ Retrieves vote polls that will end within a specified date range. | ------------------ | -------- | -------- | ----------- | | `start_time_info` | Object | No | Start time information for filtering vote polls | | `end_time_info` | Object | No | End time information for filtering vote polls | -| `limit` | Integer | No | Maximum number of results to return | -| `offset` | Integer | No | Offset for pagination | +| `limit` | Integer | No | Maximum number of results to return. See [Result limits and pagination](#result-limits-and-pagination) | +| `offset` | Integer | No | Offset for pagination. Cannot be combined with `prove`; a proof request with a non-zero `offset` is rejected | | `ascending` | Boolean | No | Sort order for results | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested vote polls | +**Response Object** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `votePollsByTimestamps` | Array | Vote polls grouped by end timestamp. Each entry has a `timestamp` and a `serializedVotePolls` array holding the serialized vote polls ending at that time | +| `finishedResults` | Boolean | `true` when the returned page is the last one for the requested range | + **Example Request and Response** ::::{tab-set} @@ -1004,6 +1080,8 @@ The request envelope is `oneof version { v0; v1; }`. Pick a version per call: | `where_clauses` (v1) / `where` (v0) | Typed (v1) or CBOR bytes (v0) | No | Filter clauses. See [Query Syntax](../reference/query-syntax.md). | | `order_by` | Typed (v1) or CBOR bytes (v0) | No | Sort order. See [Query Syntax](../reference/query-syntax.md). | | `prove` | Boolean | No | Return a proof instead of data. See [Platform proofs](../reference/platform-proofs.md). | +| `having` (v1) | Typed | No | Aggregate filters on grouped results. Present on the wire but currently rejected with `Unsupported`. See [Query Syntax](../reference/query-syntax.md). | +| `offset` (v1) | Integer | No | Row-based pagination offset. Present on the wire but currently rejected with `Unsupported`. Use `start_at` / `start_after` instead. See [Query Syntax](../reference/query-syntax.md). | For v1, see also the [doctype-level aggregate flags](../protocol-ref/data-contract-document.md#aggregate-query-flags), which control whether a document type supports the `COUNT` / `SUM` / `AVG` modes below. @@ -1015,7 +1093,7 @@ Returns matched documents. | Name | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `limit` | Integer | No | Maximum number of documents to return. | +| `limit` | Integer | No | Maximum number of documents to return. A value of `0` or an omitted value uses the configured default of 100; the [maximum is also 100](query-syntax.md#query-modifiers) by default, and a larger value is rejected with `InvalidLimit`. | | `start_at` _or_ `start_after` | Bytes | No | Cursor — start at / after this document ID. | For v1, `selects` may be omitted (defaults to `[Select{ function: DOCUMENTS }]`) or set explicitly. @@ -1197,7 +1275,7 @@ Returns one aggregate count, or per-group counts when `group_by` is set. Require | `selects` | `[Select{ function: COUNT }]` | Yes | Projection. | | `group_by` | Repeated string | No | `[]`, `[in_field]`, `[range_field]`, or `[in_field, range_field]`. | -`limit` is rejected for `group_by=[]` and `group_by=[in_field]` (the result is bounded by construction). `start_at` / `start_after` are not valid in this mode — paginate by narrowing the where clause. +`limit` is rejected for `group_by=[]` and `group_by=[in_field]` (the result is bounded by construction). `limit: 0` is rejected with `InvalidLimit` in every mode — omit the field to request the server default (SDK bindings that require a numeric argument use `-1`). `start_at` / `start_after` are not valid in this mode — paginate by narrowing the where clause. See [aggregate query limits](query-syntax.md#aggregate-query-limits) for the full per-mode contract. **Response shape** @@ -1265,7 +1343,7 @@ Returns the sum of an integer field across matched documents, or per-group sums | `selects` | `[Select{ function: SUM, field: "" }]` | Yes | `field` must name the summable property. | | `group_by` | Repeated string | No | Same shape rules as Count above. | -`start_at` / `start_after` are not valid. +`limit` follows the same rules as Count: rejected for `group_by=[]` and `group_by=[in_field]`, and `limit: 0` is rejected with `InvalidLimit` in every mode. `start_at` / `start_after` are not valid. See [aggregate query limits](query-syntax.md#aggregate-query-limits). **Response shape** @@ -1331,7 +1409,7 @@ Why `(count, sum)` instead of a single `average`? Returning the pair preserves f | `selects` | `[Select{ function: AVG, field: "" }]` | Yes | `field` must name the averageable property. | | `group_by` | Repeated string | No | Same shape rules as Count above. | -`start_at` / `start_after` are not valid. +`limit` follows the same rules as Count: rejected for `group_by=[]` and `group_by=[in_field]`, and `limit: 0` is rejected with `InvalidLimit` in every mode. `start_at` / `start_after` are not valid. See [aggregate query limits](query-syntax.md#aggregate-query-limits). **Response shape** @@ -1706,6 +1784,10 @@ grpcurl -proto protos/platform/v0/platform.proto \ ::: :::: +`balanceAndRevision` also carries a `revision` field. The example above was captured for an identity +at revision `0`, and proto3 omits zero-valued scalars from JSON output, so the field does not appear. +An identity that has been updated returns it alongside `balance`, quoted as a string. + ### getIdentityByNonUniquePublicKeyHash :::{versionadded} 2.0.0 @@ -1920,7 +2002,7 @@ Current identity contract nonce: 0 | ------- | ------- | -------- | ------------ | | `identity_id` | Bytes | Yes | An identity ID
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | `request_type` | [KeyRequestType](#request-types) | Yes | Request all keys (`all_keys`), specific keys (`specific_keys`), search for keys (`search_key`) -| `limit` | Integer | No | The maximum number of keys to return | +| `limit` | Integer | No | The maximum number of keys to return. Values above 100 are rejected with `InvalidLimit` | | `offset` | Integer | No | The offset for pagination through the keys | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested identity @@ -1948,7 +2030,7 @@ To request specific keys for an identity, use the `specific_keys` request type w **Search keys** -To search for identity keys, use the `search_keys` request type. The options for `security_Level_map` are "CURRENT_KEY_OF_KIND_REQUEST" and "ALL_KEYS_OF_KIND_REQUEST": +To search for identity keys, use the `search_key` request type. The options for `security_level_map` are "CURRENT_KEY_OF_KIND_REQUEST" and "ALL_KEYS_OF_KIND_REQUEST": ```json "search_key": { @@ -2160,7 +2242,7 @@ Retrieves the balances for a list of identities. | Name | Type | Required | Description | |-----------|---------|----------|----------------------------------------------------------| -| `ids` | Array | No | An array of identity IDs for which balances are requested
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | +| `ids` | Array | No | An array of identity IDs for which balances are requested. At most 100 IDs per call; more returns `InvalidLimit`
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | | `prove` | Boolean | No | Set to `true` to receive a proof containing the requested balances | **Example Request and Response** @@ -2191,12 +2273,12 @@ grpcurl -proto protos/platform/v0/platform.proto \ "identitiesBalances": { "entries": [ { - "identity_id": "jspLy7OhJKsoOv1C2tO9sgd7OAlll4ig8dr/zlufAB8=", - "balance": 1000000 + "identityId": "jspLy7OhJKsoOv1C2tO9sgd7OAlll4ig8dr/zlufAB8=", + "balance": "1000000" }, { - "identity_id": "dUuJ2ujbIPxM7l462wexRtfv5Qimb6Co4QlGdbnao14=", - "balance": 2500000 + "identityId": "dUuJ2ujbIPxM7l462wexRtfv5Qimb6Co4QlGdbnao14=", + "balance": "2500000" } ] }, @@ -2222,7 +2304,7 @@ grpcurl -proto protos/platform/v0/platform.proto \ | Name | Type | Required | Description | |----------------------|-------------------------|----------|-------------| -| `identities_ids` | Array | Yes | An array of identity IDs
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | +| `identities_ids` | Array | Yes | An array of identity IDs. At most 100 IDs per call; more returns `InvalidLimit`
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | | `contract_id` | Bytes | Yes | The ID of the contract | | `document_type_name` | String | No | Name of the document type | | `purposes` | Array of [KeyPurpose](#key-purposes) | No | Array of purposes for which keys are requested | @@ -2371,7 +2453,7 @@ Retrieves information about multiple groups within a contract, including their m | `start_at_group_contract_position` | Object | No | Filtering options for retrieving groups | | `start_at_group_contract_position`
`.start_group_contract_position` | UInt32 | No | The position of the first group to retrieve | | `start_at_group_contract_position`
`.start_group_contract_position_included` | Boolean | No | Whether the start position should be included in the results | -| `count` | UInt32 | No | The maximum number of groups to retrieve | +| `count` | UInt32 | No | The maximum number of groups to retrieve. See [Result limits and pagination](#result-limits-and-pagination) | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested group information | **Example Request and Response** @@ -2462,7 +2544,7 @@ Retrieves a list of actions performed by a specific group within a contract. | `start_at_action_id` | Object | No | Filtering options for retrieving actions | | `start_at_action_id.`
`start_action_id` | Bytes | No | The action ID to start retrieving from | | `start_at_action_id.`
`start_action_id_included` | Boolean | No | Whether the start action should be included in the results | -| `count` | UInt32 | No | The maximum number of actions to retrieve | +| `count` | UInt32 | No | The maximum number of actions to retrieve. See [Result limits and pagination](#result-limits-and-pagination) | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested group actions | **Returns**: A list of group actions or a cryptographic proof. The response message contains details about actions performed by a group, including various event types related to token operations, document updates, contract updates, and emergency actions. The list of possible actions is shown in the table below: @@ -2682,7 +2764,11 @@ The [`waitForStateTransitionResult` endpoint](#waitforstatetransitionresult) sho | Name | Type | Required | Description | | ------------------ | -------------- | -------- | -------------------------------------------------------------------- | -| `state_transition` | Bytes (Base64) | Yes | A [state transition](../explanations/platform-protocol-state-transition.md) | +| `state_transition` | Bytes (Base64) | Yes | A [state transition](../explanations/platform-protocol-state-transition.md). Must be non-empty and no larger than the maximum state transition size (20 KiB at protocol version 13). | + +:::{versionadded} 4.1.0 +DAPI now rejects an oversized state transition with `INVALID_ARGUMENT` before attempting to broadcast it. An empty payload is rejected the same way. The DAPI-side check is a static upper bound; Drive enforces the active protocol version's limit authoritatively, so a state transition that passes this check can still be rejected later. +::: ```{eval-rst} .. @@ -2703,9 +2789,15 @@ The [`waitForStateTransitionResult` endpoint](#waitforstatetransitionresult) sho | Name | Type | Required | Description | | ----------------------- | ------- | -------- | -------------------------------- | -| `state_transition_hash` | Bytes | Yes | Hash of the state transition | +| `state_transition_hash` | Bytes | Yes | Hash of the state transition. Must be exactly 32 bytes (the SHA-256 of the serialized state transition). | | `prove` | Boolean | Yes | Set to `true` to request a proof. The data requested will be encoded as part of the proof in the response. | +:::{versionadded} 4.1.0 +A `state_transition_hash` of any length other than 32 bytes is now rejected with `INVALID_ARGUMENT`. Previously only an empty hash was rejected, so a truncated or differently derived hash was accepted and simply never matched, causing the call to wait until it timed out. + +A node also serves a bounded number of concurrent pending waits (1,024). Once saturated, further calls return `RESOURCE_EXHAUSTED`; clients should back off and retry, or connect to a different node. +::: + **Example Request** ```{eval-rst} @@ -2774,6 +2866,18 @@ Retrieves current quorum details, including validator sets and metadata for each **Returns**: Information about current quorums, including quorum hashes, validator sets, and the last block proposer. +**Response Object** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `quorumHashes` | Array of Bytes | Hashes of all current quorums | +| `currentQuorumHash` | Bytes | Hash of the quorum currently responsible for signing | +| `validatorSets` | Array | One entry per quorum. Each has a `quorumHash`, a `coreHeight`, a `members` array, and a `thresholdPublicKey` | +| `validatorSets[].members[].proTxHash` | Bytes | ProTx hash of the validator | +| `validatorSets[].members[].nodeIp` | String | IP address of the validator | +| `validatorSets[].members[].isBanned` | Boolean | Whether the validator is banned. Omitted from JSON output when `false` | +| `lastBlockProposer` | Bytes | ProTx hash of the validator that proposed the most recent block | + **Parameters**: This endpoint does not require any parameters. @@ -2849,7 +2953,7 @@ Retrieves the number of blocks proposed by the specified evonodes in a certain e | Name | Type | Required | Description | | ------------------ | -------- | -------- | ----------- | | `epoch` | Integer | No | The epoch to query for. If not set, the current epoch will be used | -| `ids` | Array | Yes | An array of evonode IDs for which proposed blocks are retrieved IDs
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | +| `ids` | Array | Yes | An array of evonode IDs for which proposed blocks are retrieved. At most 100 IDs per call, each exactly 32 bytes
Note: masternode IDs are created uniquely as described in the [masternode identity IDs section](#masternode-identity-ids) | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested data | **Example Request and Response** @@ -2913,9 +3017,9 @@ Retrieves the number of blocks proposed by evonodes for a specified epoch. | Name | Type | Required | Description | | ------------------ | -------- | -------- | ----------- | | `epoch` | Integer | No | The epoch to query for. If not set, the current epoch will be used | -| `limit` | Integer | No | Maximum number of evonodes proposed epoch blocks to return | -| `start_after` | Bytes | No | Retrieve results starting after this document | -| `start_at` | Bytes | No | Retrieve results starting at this document | +| `limit` | Integer | No | Maximum number of evonodes proposed epoch blocks to return. See [Result limits and pagination](#result-limits-and-pagination) | +| `start_after` | Bytes | No | Retrieve results starting after this document. Mutually exclusive with `start_at` | +| `start_at` | Bytes | No | Retrieve results starting at this document. Mutually exclusive with `start_after` | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested data | **Example Request and Response** @@ -2972,8 +3076,8 @@ grpcurl -proto protos/platform/v0/platform.proto \ | Name | Type | Required | Description | | ------- | ------- | -------- | ----------- | -| `start_epoch` | Integer | No | First epoch being requested -| `count` | Integer | No | Number of records to request +| `start_epoch` | Integer | No | First epoch being requested. Must be below 65535, and `start_epoch` plus `count` must also stay below 65535; otherwise the request is rejected with `InvalidArgument` +| `count` | Integer | No | Number of records to request. The effective ceiling is 65534 minus `start_epoch` | `ascending` | Boolean | No | Set to `true` to query in ascending order. Results are returned in descending order by default. | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested data contracts @@ -3046,12 +3150,18 @@ Retrieves finalized epoch information within a specified index range. | Name | Type | Required | Description | | ---------------------------- | ------- | -------- | ----------- | -| `start_epoch_index` | Integer | No | Starting epoch index for the query | +| `start_epoch_index` | Integer | No | Starting epoch index for the query. Must not exceed 65,279. | | `start_epoch_index_included` | Boolean | No | Whether to include the `start_epoch_index` in the results | -| `end_epoch_index` | Integer | No | Ending epoch index for the query | +| `end_epoch_index` | Integer | No | Ending epoch index for the query. Must not exceed 65,279. | | `end_epoch_index_included` | Boolean | No | Whether to include the `end_epoch_index` in the results | | `prove` | Boolean | No | Set to `true` to receive a cryptographic proof instead of epoch data | +:::{versionadded} 4.1.0 +The requested range may contain at most 100 epochs, and each index must be no greater than 65,279. Exceeding either bound returns `InvalidArgument`. The `*_included` flags count toward the range size, so callers requesting a wider window must page through it in successive requests of at most 100 epochs each. + +When `start_epoch_index` and `end_epoch_index` are equal, both boundaries must be included or the request is rejected, since the range would otherwise be empty. +::: + **Example Request and Response** ::::{tab-set} @@ -3199,10 +3309,14 @@ Retrieves elements for a specified path in the platform. | Name | Type | Required | Description | | ------- | -------- | -------- | ----------- | -| `path` | Array | Yes | The path for which elements are being requested | -| `keys` | Array | No | The keys associated with the elements being requested | +| `path` | Array | Yes | The path for which elements are being requested. At most 256 components, each no larger than 255 bytes. | +| `keys` | Array | No | The keys associated with the elements being requested. At most 100 entries, each no larger than 255 bytes. | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested elements | +:::{versionadded} 4.1.0 +Requests are now bounded: at most 256 path components, at most 100 keys, at most 255 bytes per component, and at most 64 KiB for the combined byte length of all path and key components. Exceeding any of these returns `RESOURCE_EXHAUSTED`. +::: + **Example Request and Response** ::::{tab-set} @@ -3360,8 +3474,8 @@ grpcurl -proto protos/platform/v0/platform.proto \ | Name | Type | Required | Description | | ------- | ------- | -------- | ------------ | -| `start_pro_tx_hash` | Bytes | No | Protx hash of an evonode -| `count` | Integer | No | Number of records to request +| `start_pro_tx_hash` | Bytes | No | Protx hash of an evonode. Must be represented in base64 if present, and must be exactly 32 bytes; any other length is rejected with `InvalidArgument` +| `count` | Integer | No | Number of records to request. Must be below 65535 | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested protocol version vote status **Example Request and Response** @@ -3421,6 +3535,38 @@ Retrieves status information related to Dash Platform. **Returns**: Status details including version, node, chain, network, and state sync information, or a cryptographic proof. +**Response Object** + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `version.software.dapi` | String | DAPI version | +| `version.software.drive` | String | Drive version. Missing if Drive is not responding | +| `version.software.tenderdash` | String | Tenderdash version. Missing if Tenderdash is not responding | +| `version.protocol.tenderdash.p2p` | Integer | Tenderdash P2P protocol version | +| `version.protocol.tenderdash.block` | Integer | Tenderdash block protocol version | +| `version.protocol.drive.latest` | Integer | Highest protocol version supported by this node | +| `version.protocol.drive.current` | Integer | Protocol version used in the current epoch | +| `version.protocol.drive.next_epoch` | Integer | Protocol version that will be used in the next epoch | +| `node.id` | Bytes | Platform node ID | +| `node.proTxHash` | Bytes | Evonode ProTx hash. Absent if the node is a full node | +| `chain.catchingUp` | Boolean | `true` while the node is still syncing. Omitted from JSON output when `false` | +| `chain.latestBlockHash` | Bytes | Hash of the most recent block | +| `chain.latestAppHash` | Bytes | Application hash of the most recent block | +| `chain.latestBlockHeight` | String (uint64) | Height of the most recent block | +| `chain.earliestBlockHash` | Bytes | Hash of the earliest retained block | +| `chain.earliestAppHash` | Bytes | Application hash of the earliest retained block | +| `chain.earliestBlockHeight` | String (uint64) | Height of the earliest retained block | +| `chain.maxPeerBlockHeight` | String (uint64) | Highest block height reported by peers | +| `chain.coreChainLockedHeight` | Integer | Latest known core height in consensus. Missing if Drive is not responding | +| `network.chainId` | String | Name of the network | +| `network.peersCount` | Integer | Number of connected peers | +| `network.listening` | Boolean | Whether the node is accepting inbound connections | +| `stateSync` | Object | State sync progress. Empty when no state sync is in progress. Members are `totalSyncedTime`, `remainingTime`, `totalSnapshots`, `chunkProcessAvgTime`, `snapshotHeight`, `snapshotChunksCount`, `backfilledBlocks`, and `backfillBlocksTotal` | +| `time.local` | String (uint64) | Node's local time in milliseconds | +| `time.block` | String (uint64) | Most recent block time. Missing if Drive is not responding | +| `time.genesis` | String (uint64) | Genesis time. Missing if Drive is not responding | +| `time.epoch` | Integer | Current epoch. Missing if Drive is not responding | + **Parameters**: This endpoint does not require any parameters. @@ -3447,9 +3593,9 @@ grpcurl -proto protos/platform/v0/platform.proto \ "v0": { "version": { "software": { - "dapi": "1.2.0", - "drive": "1.2.0", - "tenderdash": "1.2.1" + "dapi": "4.1.0", + "drive": "4.1.0", + "tenderdash": "1.6.0" }, "protocol": { "tenderdash": { @@ -3457,36 +3603,37 @@ grpcurl -proto protos/platform/v0/platform.proto \ "block": 14 }, "drive": { - "latest": 1, - "current": 1 + "latest": 13, + "current": 13, + "nextEpoch": 13 } } }, "node": { - "id": "H/vx0yVB3Lj1VVMFKVcEqf+a3CQ=", - "proTxHash": "LkhlGi6cDLTy+3q4dAYapK8M0otZaVYx5qNa85UO9vs=" + "id": "QbMI9zfKnjn2e1UxWJAxmKiMUW4=", + "proTxHash": "s7V0hXG2D+mtEScV1qUXJdblpSqcOvX9NqFyTPUNhi8=" }, "chain": { - "latestBlockHash": "XY1U/Ay7DCdZqJJwM4sXSw1OFdBIbnVYFc9sJep1hNw=", - "latestAppHash": "9wq6IzU4AjuL27HybKqvWOOPCbnpBJQjk6q64nsd7i8=", - "latestBlockHeight": "7768", + "latestBlockHash": "pdWnS2qZPt4KW1E5AFojX3FMamipgcXLLoeAt72vfEI=", + "latestAppHash": "gK9aXNoc9ARLegnhv210Z70Yjnmphf2jANqHBdPMcpk=", + "latestBlockHeight": "505427", "earliestBlockHash": "CPoCwn7AOQujAeT8fj1+rbNQyBk+PmKgk2iXBuOiC/o=", "earliestAppHash": "vwzLnKBxugGubmegwJD5eAPSbVbWddzVExeBy8rI7I8=", "earliestBlockHeight": "1", - "maxPeerBlockHeight": "7768", - "coreChainLockedHeight": 1099682 + "maxPeerBlockHeight": "505427", + "coreChainLockedHeight": 1531571 }, "network": { "chainId": "dash-testnet-51", - "peersCount": 61, + "peersCount": 151, "listening": true }, "stateSync": {}, "time": { - "local": "1725890999274", - "block": "1725890829092", + "local": "1786373846", + "block": "1786373752393", "genesis": "0", - "epoch": 1260 + "epoch": 18061 } } } @@ -3557,7 +3704,7 @@ Retrieves token balances for a specified identity. | Name | Type | Required | Description | |-------------|---------|----------|-------------| | `identity_id` | Bytes | Yes | The ID of the identity for which token balances are requested | -| `token_ids` | Array of Bytes | No | List of token IDs to filter the balances | +| `token_ids` | Array of Bytes | No | List of token IDs to filter the balances. At most 100 entries | | `prove` | Boolean | No | Set to `true` to receive a proof containing the requested token balances | **Example Request and Response** @@ -3620,7 +3767,7 @@ Retrieves the token balances for a list of specified identities. | Name | Type | Required | Description | |-------------|---------|----------|-------------| | `token_id` | Bytes | Yes | The ID of the token whose balances are requested | -| `identity_ids` | Array of Bytes | No | A list of identity IDs to filter the balances | +| `identity_ids` | Array of Bytes | No | A list of identity IDs to filter the balances. At most 100 entries | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested token balances | **Example Request and Response** @@ -3684,7 +3831,7 @@ Retrieves information about specified tokens for a given identity. | Name | Type | Required | Description | |-------------|---------|----------|-------------| | `identity_id` | Bytes | Yes | The ID of the identity whose token information is requested | -| `token_ids` | Array of Bytes | No | A list of token IDs to retrieve information for | +| `token_ids` | Array of Bytes | No | A list of token IDs to retrieve information for. At most 100 entries | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested token information | **Example Request and Response** @@ -3749,7 +3896,7 @@ Retrieves token information for a list of specified identities. | Name | Type | Required | Description | |-------------|---------|----------|-------------| | `token_id` | Bytes | Yes | The ID of the token whose information is requested | -| `identity_ids` | Array of Bytes | No | A list of identity IDs to retrieve token information for | +| `identity_ids` | Array of Bytes | No | A list of identity IDs to retrieve token information for. At most 100 entries | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested token information | **Example Request and Response** @@ -3870,7 +4017,7 @@ This endpoint provides pricing data for tokens that support direct purchases. Ea | Name | Type | Required | Description | |-------------|----------|----------|-------------| -| `token_ids` | Array | Yes | List of 32-byte token IDs to retrieve pricing for. Must be unique and non-empty. | +| `token_ids` | Array | Yes | List of 32-byte token IDs to retrieve pricing for. Must be non-empty and contain at most 100 entries. | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested pricing data | **Example Request and Response** @@ -4039,7 +4186,7 @@ Retrieves pre-programmed distributions of a specified token. | `start_at_info.start_time_ms` | UInt64 | No | Start timestamp (in milliseconds) for filtering distributions | | `start_at_info.start_recipient` | Bytes | No | The recipient ID to start retrieving distributions from | | `start_at_info.start_recipient_included` | Boolean | No | Whether the start recipient should be included in the results | -| `limit` | UInt32 | No | Maximum number of results to return | +| `limit` | UInt32 | No | Maximum number of results to return. See [Result limits and pagination](#result-limits-and-pagination) | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested token distributions | **Example Request and Response** @@ -4121,7 +4268,7 @@ Retrieves the statuses of specified tokens. | Name | Type | Required | Description | |------------|---------|----------|-------------| -| `token_ids` | Array of Bytes | Yes | A list of token IDs to retrieve statuses for | +| `token_ids` | Array of Bytes | Yes | A list of token IDs to retrieve statuses for. At most 100 entries | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested token statuses | **Example Request and Response** @@ -4299,7 +4446,7 @@ Returns balance and nonce information for multiple addresses. | Name | Type | Required | Description | |-------------|------------------|----------|-------------| -| `addresses` | Array of Bytes | Yes | The addresses to query | +| `addresses` | Array of Bytes | Yes | The addresses to query. At most 100 addresses per request; exceeding this returns an invalid-limit error | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested address info | **Example Request and Response** @@ -4361,7 +4508,10 @@ grpcurl -proto protos/platform/v0/platform.proto \ ### getAddressesTrunkState -Returns a cryptographic proof of the trunk state of the address balance tree. Used with `getAddressesBranchState` to perform incremental sync of address balances. +Returns a cryptographic proof of the trunk state of the address balance tree. Used with [`getAddressesBranchState`](#getaddressesbranchstate) to perform incremental sync of address +balances. + +The trunk proof is served from the latest available checkpoint rather than from current state, so the returned `metadata.height` is a checkpoint height that generally trails the chain tip. The quorum signature, `blockIdHash`, and round in the proof correspond to that checkpoint height as well, so verifiers must resolve the signing quorum at the checkpoint height rather than at the tip. Pass the returned height as `checkpoint_height` on follow-up [`getAddressesBranchState`](#getaddressesbranchstate) calls; branch proofs are served only from checkpoints, so a height that no longer has a checkpoint returns an error. **Returns**: A cryptographic proof of the address tree trunk state. @@ -4453,10 +4603,17 @@ grpcurl -proto protos/platform/v0/platform.proto \ ::: :::: +Use the `checkpoint_height` from the preceding `getAddressesTrunkState` response to ensure the +branch proof corresponds to the same checkpoint. + ### getRecentAddressBalanceChanges Returns address balance changes starting from a specified block height. Supports both inclusive and exclusive start heights for incremental sync. +A single call returns changes for at most 100 blocks. If the response contains 100 blocks, more +changes may remain: page forward by re-issuing the call with `start_height` set to the highest +`blockHeight` returned and `start_height_exclusive` set to `true`. + **Returns**: A list of address balance changes grouped by block, or a cryptographic proof. **Parameters**: @@ -4530,6 +4687,10 @@ grpcurl -proto protos/platform/v0/platform.proto \ Returns compacted address balance changes from a specified block height. Compacted changes merge multiple operations per address into a single entry per block range, reducing response size for bulk sync. +A single call returns at most 25 compacted block-range entries, a bound chosen to keep proofs within +their size limit. If the response contains 25 entries, page forward by re-issuing the call with +`start_block_height` set past the `endBlockHeight` of the last entry returned. + **Returns**: A list of compacted address balance changes grouped by block range, or a cryptographic proof. **Parameters**: @@ -4541,6 +4702,9 @@ Returns compacted address balance changes from a specified block height. Compact **Example Request and Response** +The example response below was captured at protocol version 11. At protocol version 13 and above, +proof responses use the [compacted proof encoding described in Platform Proofs](platform-proofs.md#compacted-address-balance-proofs). + ::::{tab-set} :::{tab-item} gRPCurl ```shell @@ -4577,6 +4741,15 @@ grpcurl -proto protos/platform/v0/platform.proto \ ::: :::: +The example above was captured for a range with no balance changes, so +`compactedAddressBalanceUpdateEntries` is empty. When changes are present it contains a +`compactedBlockChanges` array; each element has a `startBlockHeight`, an `endBlockHeight`, and a +`changes` array. Each entry in `changes` carries an `address` plus exactly one of `setCredits` (the +final balance for the range) or `addToCreditsOperations` (the individual adds, each tagged with its +block height, so a client can apply only those above its own sync height). Note that these names +differ from the `setBalance` and `addToBalance` fields used by +[`getRecentAddressBalanceChanges`](#getrecentaddressbalancechanges). + ## Shielded Transaction Endpoints :::{versionadded} 4.0.0 @@ -4592,10 +4765,16 @@ Returns encrypted notes from the shielded pool for a specified range. Clients us | Name | Type | Required | Description | |---------------|---------|----------|-------------| -| `start_index` | Integer | Yes | The index of the first note to retrieve | -| `count` | Integer | Yes | The number of notes to retrieve | +| `start_index` | Integer | Yes | The index of the first note to retrieve. Must be chunk-aligned: a multiple of the note commitment tree's MMR chunk size (2048). A non-aligned value is rejected with `InvalidArgument` | +| `count` | Integer | Yes | The number of notes to retrieve, capped at 8,192 (4 MMR chunks of 2,048 notes each). A `count` of `0` or one above the cap is silently treated as a request for the maximum rather than rejected | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested notes | +Because `start_index` must land on an MMR chunk boundary, paginate by advancing `start_index` in +multiples of the chunk size rather than by the number of notes actually returned. + +A response containing fewer notes than requested means the end of the note commitment tree was +reached, not that the response was truncated. Stop paginating when this occurs. + **Example Request and Response** ::::{tab-set} @@ -4654,7 +4833,7 @@ grpcurl -proto protos/platform/v0/platform.proto \ ### getShieldedAnchors -Returns all commitment tree anchors for the shielded pool. Anchors are used by shielded transaction provers to reference a valid state of the commitment tree. +Returns the commitment tree anchors currently retained by the node for the shielded pool. Anchors are used by shielded transaction provers to reference a valid state of the commitment tree. **Returns**: A list of commitment tree anchors or a cryptographic proof. @@ -4664,6 +4843,12 @@ Returns all commitment tree anchors for the shielded pool. Anchors are used by s |---------|---------|----------|-------------| | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested anchors | +The response covers the [node's retention window](../protocol-ref/shielded-pool.md#anchors) rather than the full history of the pool: older anchors are pruned, so the retained set is bounded by the retention and pruning policy. + +:::{versionadded} 4.1.0 +If the retained anchor set exceeds what this unpaginated response can enumerate, the call returns `RESOURCE_EXHAUSTED` instead of doing unbounded work. Retry with backoff; if the condition persists, try another node rather than repeatedly retrying the same one. +::: + **Example Request and Response** ::::{tab-set} @@ -4721,6 +4906,10 @@ Returns the most recent commitment tree anchor for the shielded pool. |---------|---------|----------|-------------| | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested anchor | +If no anchor has been recorded on the chain yet, the unproved response returns an all-zero 32-byte +`anchor` as an "absent" sentinel rather than omitting the field or returning an error. Treat an +all-zero anchor as "no anchor available" and do not use it for proof generation. + **Example Request and Response** ::::{tab-set} @@ -4872,7 +5061,7 @@ Returns the spent status of specified nullifiers. Clients use this to determine | Name | Type | Required | Description | |--------------|----------------|----------|-------------| -| `nullifiers` | Array of Bytes | Yes | The nullifiers to query (each 32 bytes) | +| `nullifiers` | Array of Bytes | Yes | The nullifiers to query. Must contain between 1 and 100 entries, each exactly 32 bytes. An empty list or a wrong-length entry is rejected with `InvalidArgument`; more than 100 entries is rejected as an invalid limit | | `prove` | Boolean | No | Set to `true` to receive a proof that contains the requested nullifier statuses | **Example Request and Response** @@ -4930,5 +5119,5 @@ A nullifier's `is_spent` field is omitted from the response when `false` (proto3 Implementation details related to the information on this page can be found in: -* The [Platform repository](https://github.com/dashpay/platform/tree/master/packages/dapi) `packages/dapi/lib/grpcServer/handlers/core` folder +* The [Platform repository](https://github.com/dashpay/platform/tree/master/packages/rs-dapi/src/services) `packages/rs-dapi/src/services` folder, which contains the DAPI implementation deployed by dashmate * The [Platform repository](https://github.com/dashpay/platform/tree/master/packages/dapi-grpc) `packages/dapi-grpc/protos` folder diff --git a/docs/reference/dapi-endpoints.md b/docs/reference/dapi-endpoints.md index 188789b23..04790916d 100644 --- a/docs/reference/dapi-endpoints.md +++ b/docs/reference/dapi-endpoints.md @@ -35,6 +35,7 @@ without introducing issues for endpoint consumers. | [`getDataContracts`](../reference/dapi-endpoints-platform-endpoints.md#getdatacontracts) | Returns the requested data contracts | | [`getDataContractHistory`](../reference/dapi-endpoints-platform-endpoints.md#getdatacontracthistory) | Returns the requested data contract history | | [`getDocuments`](../reference/dapi-endpoints-platform-endpoints.md#getdocuments) | **Updated in Dash Platform v4.0.0**
Returns the requested document(s), or an aggregate count/sum/average over the matched document set. | +| [`getDocumentHistory`](../reference/dapi-endpoints-platform-endpoints.md#getdocumenthistory) | **Added in Dash Platform v4.0.0**
Returns the revision history for a single document on a contract that keeps document history | ### Identities @@ -154,10 +155,15 @@ The following endpoints provide information about the Core chain. ### JSON-RPC Endpoints +These endpoints historically expose Core information; `getStatus` is the exception and returns +Platform status. + | Endpoint | Description | | -------- | ----------- | | [`getBestBlockHash`](../reference/dapi-endpoints-json-rpc-endpoints.md#getbestblockhash) | Returns block hash of the chaintip | | [`getBlockHash`](../reference/dapi-endpoints-json-rpc-endpoints.md#getblockhash) | Returns block hash of the requested block | +| [`getStatus`](../reference/dapi-endpoints-json-rpc-endpoints.md#getstatus) | Returns Platform status information | +| [`sendRawTransaction`](../reference/dapi-endpoints-json-rpc-endpoints.md#sendrawtransaction) | Submits a raw transaction to the network | ### gRPC Endpoints @@ -165,9 +171,9 @@ The following endpoints provide information about the Core chain. | -------- | ----------- | | [`broadcastTransaction`](../reference/dapi-endpoints-core-grpc-endpoints.md#broadcasttransaction) | Broadcasts the provided transaction | | [`getBestBlockHeight`](../reference/dapi-endpoints-core-grpc-endpoints.md#getbestblockheight) | *Added in Dash Platform v1.0.0*
Return the best block height| -| [`getBlock`](../reference/dapi-endpoints-core-grpc-endpoints.md#getblock) | **Disabled in Dash Platform v1.0.0**
Returns information for the requested block | +| [`getBlock`](../reference/dapi-endpoints-core-grpc-endpoints.md#getblock) | Returns information for the requested block | | [`getBlockchainStatus`](../reference/dapi-endpoints-core-grpc-endpoints.md#getblockchainstatus) | *Added in Dash Platform v1.0.0*
Returns blockchain status information | -| [`getMasternodeStatus`](../reference/dapi-endpoints-core-grpc-endpoints.md#getmasternodestatus) | **Disabled in Dash Platform v1.0.0**
Returns masternode status information | +| [`getMasternodeStatus`](../reference/dapi-endpoints-core-grpc-endpoints.md#getmasternodestatus) | Returns masternode status information | | [`getTransaction`](../reference/dapi-endpoints-core-grpc-endpoints.md#gettransaction) | Returns details for the requested transaction | | [`subscribeTo` `BlockHeadersWithChainLocks`](../reference/dapi-endpoints-core-grpc-endpoints.md#subscribetoblockheaderswithchainlocks) | Returns the requested block headers along with the associated ChainLocks. | | [`subscribeToMasternodeList`](../reference/dapi-endpoints-core-grpc-endpoints.md#subscribetomasternodelist) | *Added in Dash Platform v1.0.0*
Returns the full masternode list from the genesis block to the chain tip as the first message and provides update messages with every new block | @@ -175,7 +181,7 @@ The following endpoints provide information about the Core chain. :::{note} The previous version of documentation can be [viewed -here](https://docs.dash.org/projects/platform/en/2.0.0/docs/reference/dapi-endpoints.html). +here](https://docs.dash.org/projects/platform/en/4.0.0/docs/reference/dapi-endpoints.html). ::: ```{toctree} diff --git a/docs/reference/data-contracts.md b/docs/reference/data-contracts.md index 4302afb7d..c82c78f3c 100644 --- a/docs/reference/data-contracts.md +++ b/docs/reference/data-contracts.md @@ -35,6 +35,7 @@ Data contracts support three categories of configuration options to provide flex | `canBeDeleted` | `false` | Determines if the contract can be deleted | | `readonly` | `false` | Determines if the contract is read-only. Read-only contracts cannot be updated. | | `keepsHistory` | `false` | Enables or disables the storing of contract update history | +| `sized_integer_types` | `true` | Use sized integer types for `integer` properties based on their validation rules. Note that this key is snake_case, unlike the other contract configuration keys. | | Document default option | Default | Description | |-----------------------------------------|---------|-------------| @@ -46,6 +47,7 @@ Data contracts may also define the following top-level fields: | Contract field | Type | Description | |----------------|------|-------------| +| `tokens` | object | (Optional) Token definitions keyed by token contract position. Each entry configures base supply, maximum supply, minting and burning rules, and change control. See [Contract Tokens](../protocol-ref/data-contract-token.md). | | `groups` | object | (Optional) Groups that allow for specific multiparty actions on the contract. See [Data Contract groups](../protocol-ref/data-contract.md#data-contract-groups). | | `keywords` | array of strings | (Optional) Keywords associated with the contract to improve searchability via the `search` system contract. Maximum of 50 unique keywords. | | `description` | string | (Optional) Brief human-readable description of the contract (3-100 characters). Also added to the `search` system contract. | @@ -106,6 +108,9 @@ Documents support the following configuration options to provide flexibility in | `transferable` | integer | Transferable without a marketplace sell:
`0` - Never
`1` - Always
See the [NFT page](../explanations/nft.md#transfer-and-trade) for more details | | `tradeMode` | integer | Built-in marketplace system:
`0` - None
`1` - Direct purchase (the purchaser can buy the item without requiring approval)
See the [NFT page](../explanations/nft.md#transfer-and-trade) for more details | | `creationRestrictionMode` | integer | Restriction of document creation:
`0` - No restrictions
`1` - Contract owner only
`2` - No Creation Allowed
See the [NFT page](../explanations/nft.md#creation-restrictions) for more details | +| `keepsTransferHistory` | boolean | If true, transfers of these documents are recorded in the document history system contract. Default: false. | +| `keepsPurchaseHistory` | boolean | If true, purchases of these documents are recorded in the document history system contract. Default: false. | +| `keepsPricingHistory` | boolean | If true, price updates on these documents are recorded in the document history system contract. Default: false. | | Security option | Type | Description | |-----------------|------|-------------| @@ -121,7 +126,7 @@ Document types can opt into aggregate queries with the flags `documentsCountable :::{dropdown} List of all usable document properties - This list of properties is defined in the [Rust DPP implementation](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/src/data_contract/document_type/mod.rs#L31) and the [document meta-schema](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json). + This list of properties is defined in the [Rust DPP implementation](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/src/data_contract/document_type/mod.rs#L31) and the [document meta-schema](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json). | Property Name | Type | Description | |---------------|------|-------------| @@ -136,6 +141,9 @@ Document types can opt into aggregate queries with the flags `documentsCountable | `transferable` | integer | Transferable without a marketplace sell:
`0` - Never
`1` - Always | | `tradeMode` | integer | Built-in marketplace system:
`0` - None
`1` - Direct purchase (the purchaser can buy the item without requiring approval) | | `creationRestrictionMode` | integer | Restriction of document creation:
`0` - No restrictions
`1` - Contract owner only
`2` - No Creation Allowed. | + | `keepsTransferHistory` | boolean | If true, transfers of these documents are recorded in the document history system contract. Default: false. | + | `keepsPurchaseHistory` | boolean | If true, purchases of these documents are recorded in the document history system contract. Default: false. | + | `keepsPricingHistory` | boolean | If true, price updates on these documents are recorded in the document history system contract. Default: false. | | [`requiresIdentity`
`EncryptionBoundedKey`](#key-management) | integer | Key requirements for identity encryption:
`0` - Unique non-replaceable
`1` - Multiple
`2` - Multiple with reference to latest key | | [`requiresIdentity`
`DecryptionBoundedKey`](#key-management) | integer | Key requirements for identity decryption:
`0` - Unique non-replaceable
`1` - Multiple
`2` - Multiple with reference to latest key | | [`properties`](#document-properties) | object | Defines the properties of the document. | @@ -152,7 +160,7 @@ Document types can opt into aggregate queries with the flags `documentsCountable **Example** -The following example (from the [DPNS contract's `domain` document](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json)) demonstrates the use of several configuration options: +The following example (from the [DPNS contract's `domain` document](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json)) demonstrates the use of several configuration options: ```json { @@ -161,6 +169,9 @@ The following example (from the [DPNS contract's `domain` document](https://gith "canBeDeleted": true, "transferable": 1, "tradeMode": 1, + "keepsTransferHistory": true, + "keepsPurchaseHistory": true, + "keepsPricingHistory": true, "..." } } @@ -178,10 +189,10 @@ There are a variety of constraints currently defined for performance and securit | Description | Value | | ----------- | ----- | -| Minimum number of properties | [1](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L22) | -| Maximum number of properties | [100](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L23) | -| Minimum property name length | [1](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L9) | -| Maximum property name length | [64](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L9) | +| Minimum number of properties | [1](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L23) | +| Maximum number of properties | [100](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L24) | +| Minimum property name length | [1](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L21) | +| Maximum property name length | [64](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L21) | | Property name characters | Alphanumeric (`A-Z`, `a-z`, `0-9`)
Hyphen (`-`)
Underscore (`_`) | #### Assigning property `position` @@ -245,7 +256,7 @@ Each document may have transient fields that require validation but do not need **Example** -The following example (from the [DPNS contract's `domain` document](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json)) demonstrates a document that has 1 transient field: +The following example (from the [DPNS contract's `domain` document](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json)) demonstrates a document that has 1 transient field: ```json "transient": [ @@ -318,7 +329,7 @@ The table below describes the properties used to configure a contested index: **Example** -This example (from the [DPNS contract's `domain` document](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json)) demonstrates the use of a contested index: +This example (from the [DPNS contract's `domain` document](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json)) demonstrates the use of a contested index: ``` json "contested": { @@ -339,10 +350,10 @@ For performance and security reasons, indices have the following constraints. Th | Description | Value | | ----------- | ----- | -| Minimum / maximum length of index `name` | [1](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L311) / [32](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L312) | -| Maximum number of indices | [10](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L390) | +| Minimum / maximum length of index `name` | [1](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L358) / [32](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L359) | +| Maximum number of indices | [10](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L482) | | Maximum number of unique indices | [10](https://github.com/dashpay/platform/blob/master/packages/rs-platform-version/src/version/v1.rs#L989) | -| Maximum number of properties in a single index | [10](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L331) | +| Maximum number of properties in a single index | [10](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L378) | | Maximum length of indexed string property | [63](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs#L72) | | Maximum length of indexed byte array property | [255](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs#L73) | | Maximum number of indexed array items | [1024](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs#L74) | @@ -441,7 +452,7 @@ This example syntax shows the structure of a document object including all optio ## General Constraints -There are a variety of constraints currently defined for performance and security reasons. The following constraints are applicable to all aspects of data contracts. Unless otherwise noted, these constraints are defined in the platform's JSON Schema rules (e.g. [rs-dpp document meta schema](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json)). +There are a variety of constraints currently defined for performance and security reasons. The following constraints are applicable to all aspects of data contracts. Unless otherwise noted, these constraints are defined in the platform's JSON Schema rules (e.g. [rs-dpp document meta schema](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json)). ### Keyword @@ -449,13 +460,14 @@ There are a variety of constraints currently defined for performance and securit | ------- | ---------- | | `default` | Restricted - cannot be used (defined in DPP logic) | | `propertyNames` | Restricted - cannot be used (defined in DPP logic) | -| `uniqueItems: true` | `maxItems` must be defined (maximum: 100000) | -| `pattern: ` | `maxLength` must be defined (maximum: [50000](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L187)) | -| `format: ` | `maxLength` must be defined (maximum: [50000](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json#L200)) | -| `$ref: ` | Disabled for data contracts | +| `pattern: ` | `maxLength` must be defined (maximum: [50000](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L188)) | +| `format: ` | `maxLength` must be defined (maximum: [50000](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v2/document-meta.json#L201)) | +| `$ref: ` | Internal references only - the value must begin with `#` (e.g. `#/$defs/myType`). External and remote references, and reference cycles, are rejected | | `if`, `then`, `else`, `allOf`, `anyOf`, `oneOf`, `not` | Disabled for data contracts | -| `dependencies` | Not supported. Use `dependentRequired` and `dependentSchema` instead | -| `additionalItems` | Not supported. Use `items: false` and `prefixItems` instead | +| `dependencies` | Not supported. Use `dependentRequired` instead | +| `dependentSchemas` | Not supported. Schema-based dependencies are not available in document schemas; use `dependentRequired` for property-presence dependencies | +| `type: array` | Only byte arrays are supported. `byteArray: true` must be defined; schemas for individual array items are not available | +| `additionalItems` | Not supported. Per-item array schemas (`items` / `prefixItems`) are not available in document schemas; constrain arrays with `minItems`, `maxItems`, `uniqueItems`, `contains`, and `byteArray` | | `patternProperties` | Restricted - cannot be used for data contracts | | `pattern` | Accept only [RE2](https://github.com/google/re2/wiki/Syntax) compatible regular expressions (defined in DPP logic) | @@ -463,7 +475,9 @@ There are a variety of constraints currently defined for performance and securit **Note:** These constraints are defined in the Dash Platform Protocol logic (not in JSON Schema). -All serialized data (including state transitions) is limited to a maximum size of [16 KB](https://github.com/dashpay/platform/blob/master/packages/rs-dpp/src/util/cbor_serializer.rs#L8). +A state transition is limited to a maximum size of [20 KiB](https://github.com/dashpay/platform/blob/v4.1.0/packages/rs-platform-version/src/version/system_limits/v3.rs) (`max_state_transition_size`). Oversized transitions are rejected. + +An individual document field value is limited to [5 KiB](https://github.com/dashpay/platform/blob/v4.1.0/packages/rs-platform-version/src/version/system_limits/v3.rs) (`max_field_value_size`). ### Additional Properties diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index d19e2b896..395c2036d 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -38,7 +38,9 @@ Layer 1 blockchain used for payments, governance, and providing the foundation f ## Credits -Means of paying fees on the layer 2 platform +Means of paying fees on the layer 2 platform. Credits are the smallest unit of account on Platform: +1 duff = 1,000 credits, and 1 Dash = 100,000,000,000 credits. See [Protocol +constants](../protocol-ref/protocol-constants.md#credit-system) for the full conversion table. ## DAPI @@ -46,7 +48,9 @@ Dash's decentralized API for interacting with the core blockchain (layer 1) and ## DAPI Client -An HTTP Client that connects to DAPI to enable users to read and write data to the Dash platform +A client that connects to DAPI to read and write Platform data or access Core chain information. +DAPI exposes gRPC services for Platform and Core, plus JSON-RPC for selected Core information and +Platform status. ## DashPay @@ -118,6 +122,26 @@ An epoch is a fixed time period used to organize and manage blockchain operation An era consists of 40 [epochs](#epoch) and equals approximately one year. At the end of an era, Dash Platform may optionally do additional accounting or reconfiguration. +## Evonode + +An evolution masternode: a [masternode](#masternode) that meets the additional collateral and hardware requirements to run Dash Platform services alongside Dash Core. Only evonodes participate in the [validator set](#validator-set) that produces Platform blocks, and evonode operators receive Platform block rewards for that participation. + +## Group (data contract) + +A set of identities defined in a [data contract](#data-contract) that jointly authorize actions on that contract, such as token minting or configuration changes. Each member is assigned a voting power, and an action executes once the members approving it reach the group's required power threshold. Distinct from a [quorum](#quorum), which is a set of masternodes selected by the network to sign protocol-level actions. + +## History (contract revision) + +The record of successive revisions of a [data contract](#data-contract), retained when the contract sets `keepsHistory` at creation. Retrieved with [`getDataContractHistory`](../reference/dapi-endpoints-platform-endpoints.md#getdatacontracthistory). This tracks changes to the contract definition itself, not to the documents stored under it. See [Retrieve data contract history](../tutorials/contracts-and-documents/retrieve-data-contract-history.md). + +## History (document revision) + +The record of successive revisions of an individual [document](#document), retained when its document type sets `documentsKeepHistory`. Retrieved with [`getDocumentHistory`](../reference/dapi-endpoints-platform-endpoints.md#getdocumenthistory). This tracks edits to a document's own fields, not its transfers or sales. + +## History (document ownership and pricing) + +The record of transfers, purchases and price updates for documents, written to the [document history system contract](../protocol-ref/data-contract.md#document-history-system-contract). Document types opt in with the [document history flags](../protocol-ref/data-contract-document.md#document-history-flags) `keepsTransferHistory`, `keepsPurchaseHistory` and `keepsPricingHistory`. This is separate from both revision histories above: it records ownership and pricing events rather than changes to contract or document content. + ## Layer (1, 2, 3) - Layer 1: Core blockchain and [Dash Core](#dash-core) @@ -146,7 +170,7 @@ Layer 2 blockchain that propagates platform data among masternodes, propagates p ## Platform State -All layer 2 data including contracts, documents (user data), tokens, groups, credit balance, identity (username), and masternode voting/contested resource state +All layer 2 data including contracts, documents (user data), tokens, groups, credit balance, identity (username), address balances, shielded pool state, and masternode voting/contested resource state ## practical Byzantine Fault Tolerance (pBFT) @@ -186,7 +210,7 @@ The application that validates state transitions and updates state in Drive ## State Transition -A signed change to platform state submitted by an identity. State transitions cover a range of operations, including data contract creation and updates, document and token changes (batched), identity lifecycle operations (create, top-up, update), credit transfers and withdrawals, and masternode voting (cast by masternode and evonode operators) +A signed change to platform state. Most state transitions are submitted by an identity, but some are not owned by one - the address-system and shielded-pool transitions carry no owner identity. State transitions cover a range of operations, including data contract creation and updates, document and token changes (batched), identity lifecycle operations (create, top-up, update), credit transfers and withdrawals, address-system and shielded-pool operations, and masternode voting (cast by masternode and evonode operators) ## Tenderdash diff --git a/docs/reference/platform-proofs.md b/docs/reference/platform-proofs.md index 2061862de..226563926 100644 --- a/docs/reference/platform-proofs.md +++ b/docs/reference/platform-proofs.md @@ -11,16 +11,16 @@ agreed upon by the validator network -- without trusting whoever supplied the da The most common way to obtain a proof is to request one over [DAPI](../explanations/dapi.md): set the optional `"prove": true` parameter on a [Platform gRPC endpoint](../reference/dapi-endpoints-platform-endpoints.md) and the response carries a `Proof` -message instead of the plain result. A proof does not depend on how it was retrieved, though -- -it can be verified independently by any party that holds it. +message instead of the plain result. A proof does not depend on how it was retrieved. It +can be verified independently by any party that holds it. For the concepts behind proofs -- the two-layer GroveDB + consensus trust model, the verification flow, what can be proven, and asset lock proofs -- see [Proofs](../explanations/proofs.md). ## Proof structure -A `Proof` is a single unified [GroveDB](https://github.com/dashpay/grovedb) proof plus the -consensus signature that authenticates it. It has six fields: +A `Proof` is a unified [GroveDB](https://github.com/dashpay/grovedb) proof plus the consensus +signature that authenticates it. It has six fields: | Field | Type | Description | | - | - | - | @@ -44,13 +44,20 @@ consensus signature that authenticates it. It has six fields: } ``` +Two endpoint families depart from this standard structure: compacted address balance proofs use a +version-dependent `grovedbProof` encoding, while address-tree sync endpoints use different +proof-bearing response shapes. See [Proof internals](#proof-internals) and [Address tree sync +verification](#address-tree-sync-verification), respectively. + ## Verifying proofs -Clients do not parse proofs manually. Verification is performed by the -`rs-drive-proof-verifier` crate, which checks the quorum's BLS threshold signature (the -Tenderdash consensus half) and decodes the unified `grovedbProof` to recover the requested data -and the state root hash. This logic is exposed to JavaScript and browser clients through the -`wasm-drive-verify` package, so the SDKs verify proofs automatically whenever one is requested. +Dash Platform SDKs parse and verify standard requested proofs automatically. Verification is +performed by the `rs-drive-proof-verifier` crate, which checks the quorum's BLS threshold +signature (the Tenderdash consensus half) and decodes the unified `grovedbProof` to recover the +requested data and the state root hash. Direct clients must also handle the protocol-specific +compacted proof envelope and bare `merkProof` paths described below. Applications performing +verification directly can use `rs-drive-proof-verifier`; JavaScript and browser applications can +use the available WebAssembly bindings. See the [Proofs](../explanations/proofs.md) explanation for the step-by-step verification flow. @@ -62,6 +69,42 @@ is documented in the [GroveDB Proof System documentation](https://dashpay.github.io/grovedb/proof-system.html). Clients that use an SDK do not need to work at this level. +### Compacted address balance proofs + +:::{versionchanged} 4.1.0 +At protocol version 13 and above, the `grovedbProof` returned by +[`getRecentCompactedAddressBalanceChanges`](../reference/dapi-endpoints-platform-endpoints.md#getrecentcompactedaddressbalancechanges) +is not a single GroveDB proof. It is a [bincode envelope carrying two independent GroveDB +proofs](https://github.com/dashpay/platform/blob/v4.1.0/packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/mod.rs#L21-L30): + +- a **predecessor proof**, which authenticates which compacted range contains the requested start height, and +- a **forward proof**, verified against a query derived only from that authenticated result. + +Both proofs must commit to the same state root hash. Binding the forward query's start key to an +independently verified predecessor result makes this trust model slightly stronger than the +single-proof case. Protocol version 12 and below use the legacy single-proof format for this +response. + +A verifier written for the single-proof model will fail to decode a protocol version 13 compacted +proof, so clients implementing verification outside the provided SDKs must handle both formats and +select by protocol version. +::: + +## Address tree sync verification + +The two address-tree sync endpoints used for incremental address balance sync differ from the rest +of the Platform surface. Neither takes a `prove` parameter; both always return proof data. + +[`getAddressesTrunkState`](../reference/dapi-endpoints-platform-endpoints.md#getaddressestrunkstate) +returns a standard `Proof` message plus response metadata. Because the proof is anchored to the +returned checkpoint height rather than the chain tip, a verifier must resolve the signing quorum +at that checkpoint height or signature verification will fail. + +[`getAddressesBranchState`](../reference/dapi-endpoints-platform-endpoints.md#getaddressesbranchstate) +is the further exception: its response carries neither a `Proof` message nor a `metadata` block, +only a bare `merkProof` byte string with no signature of its own. See the endpoint references for +the checkpoint workflow and request/response details. + ## Related topics - [Proofs](../explanations/proofs.md) -- the conceptual trust model, verification flow, and asset lock proofs diff --git a/docs/reference/query-syntax.md b/docs/reference/query-syntax.md index 63d2b35b3..0fb18ffab 100644 --- a/docs/reference/query-syntax.md +++ b/docs/reference/query-syntax.md @@ -26,12 +26,12 @@ The Where clause is an optional array of conditions. If omitted or empty, all do ### Fields -Valid fields consist of the indices defined for the document being queried. For example, the [DPNS data contract](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json) defines two indices for domain documents: +Valid fields consist of the indices defined for the document being queried. For example, the [DPNS data contract](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json) defines two indices for domain documents: | Index Field(s) | Index Type | Unique | | - | - | :-: | -| [normalizedParentDomainName, normalizedLabel](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json#L11-L18) | Compound | Yes | -| [records.identity](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json#L31-L39) | Single Field | No | +| [normalizedParentDomainName, normalizedLabel](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json#L12-L33) | Compound | Yes | +| [records.identity](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json#L34-L42) | Single Field | No | ```{eval-rst} .. @@ -59,19 +59,19 @@ Valid fields consist of the indices defined for the document being queried. For | <= | Matches values that are less than or equal to a specified value | | >= | Matches values that are greater than or equal to a specified value | | > | Matches values that are greater than a specified value | -| in | Matches all document(s) where the value of the field equals any value in the specified array
Array may include up to 100 (unique) elements | +| in | Matches all document(s) where the value of the field equals any value in the specified array
The array must contain between 1 and 100 values, with no duplicates. Empty arrays, oversized arrays, and duplicate values are rejected with `InvalidInClause` | | Between | Matches values between two bounds (inclusive on both sides) — value must be a two-element array `[lower, upper]` with `lower < upper` | | BetweenExcludeBounds | Matches values strictly between two bounds (exclusive on both sides) | | BetweenExcludeLeft | Matches values between two bounds, excluding the lower bound | | BetweenExcludeRight | Matches values between two bounds, excluding the upper bound | -:::{tip} -- Only one range operator is allowed in a query. `Between` and its variants are single operators that replace a `>=`/`<=` pair — the engine also normalizes two range operators on the same field into the equivalent `Between*` form automatically +**Range operator constraints** + +- A query can have only one effective range clause. Use `Between` or one of its variants to express both bounds, or supply two complementary range clauses on the same field; Platform normalizes the pair to the equivalent `Between*` form - The `in` operator is only allowed for last two indexed properties - Range operators apply to an indexed field that follows any `==` and `in` clauses in the index. A standalone range (with no preceding `==`/`in` clause) is valid when a matching index exists - Range operators are only allowed for the last two fields used in the where condition - Queries using range operators (including `in`, which is treated as a range) must also include an `orderBy` statement -::: ### Evaluation Operators @@ -79,6 +79,20 @@ Valid fields consist of the indices defined for the document being queried. For | :-: | - | | startsWith | Selects documents where the value of a field begins with the specified characters. Must include an `orderBy` statement. | +### Operator aliases + +Operator names are matched against a fixed set of aliases: + +| Operator | Accepted aliases | +| - | - | +| `==` | `=` | +| `in` | `In` | +| `Between` | `between` | +| `BetweenExclude*` | CamelCase, lowercase, and snake_case variants, such as `betweenExcludeLeft`, `betweenexcludeleft`, and `between_exclude_left` | +| `startsWith` | `StartsWith`, `startswith`, `starts_with` | + +Any other spelling is rejected. + ### Operator Examples :::::{tab-set} @@ -157,14 +171,27 @@ The query modifiers described here determine how query results will be sorted an | Modifier | Effect | Example | | - | - | - | -| `limit` | Restricts the number of results returned (maximum: 100) | `limit: 10` | -| `orderBy` | Returns records sorted by the field(s) provided. The `orderBy` fields must match a consecutive run of the index's properties, read from the end of the index (for a compound index, sort by one or more of its trailing fields). Can only be used with `>`, `<`, `>=`, `<=`, `Between`, `BetweenExcludeBounds`, `BetweenExcludeLeft`, `BetweenExcludeRight`, and `startsWith` queries. | `orderBy: [['normalizedLabel', 'asc']]` | +| `limit` | Restricts the number of documents returned. An omitted value or `0` uses the configured default (100 by default). Positive values cannot exceed the configured maximum (also 100 by default). See [Aggregate query limits](#aggregate-query-limits) for aggregate result modes. | `limit: 10` | +| `orderBy` | Returns records sorted by the field(s) provided. The `orderBy` fields must match a consecutive run of the index's properties, read from the end of the index (for a compound index, sort by one or more of its trailing fields). Can only be used with `>`, `<`, `>=`, `<=`, `in`, `Between`, `BetweenExcludeBounds`, `BetweenExcludeLeft`, `BetweenExcludeRight`, and `startsWith` queries. | `orderBy: [['normalizedLabel', 'asc']]` | | `startAt` | Returns records beginning with the document ID provided | `startAt: ''` | | `startAfter` | Returns records beginning after the document ID provided | `startAfter: ''` | -| `offset` | Skips the first N matching results (available at the CBOR/DAPI layer; not exposed in the JS SDK) | `offset: 10` | +| `offset` | Present on the wire but currently rejected with `Unsupported`. Use `startAt` or `startAfter` for pagination. | n/a | + +### Ordering compound indexes + +For indices composed of multiple fields ([example from the DPNS data contract](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v2/dpns-contract-documents.json)), the sort order in an `orderBy` must either match the order defined in the data contract OR be the inverse order. + +### Combining a cursor with a range operator + +This behavior applies when returning `DOCUMENTS`; aggregate result modes do not support cursors. + +When a `startAt` / `startAfter` cursor is combined with a range operator (`>`, `>=`, `<`, `<=`), the cursor narrows the effective range in the direction of the `orderBy` sort: -:::{attention} -For indices composed of multiple fields ([example from the DPNS data contract](https://github.com/dashpay/platform/blob/master/packages/dpns-contract/schema/v1/dpns-contract-documents.json)), the sort order in an `orderBy` must either match the order defined in the data contract OR be the inverse order. +- Ascending order — the cursor is the lower bound and the range clause's value is the upper bound. `startAfter` excludes the cursor row itself. +- Descending order — the roles invert: the range clause's value is the lower bound and the cursor is the upper bound. + +:::{versionchanged} 4.1.0 +Ascending queries that combined a cursor with a `<` or `<=` clause previously [built their range backwards](https://github.com/dashpay/platform/blob/v4.1.0/packages/rs-drive/src/query/conditions.rs#L944-L990), returning incorrect or empty results. Paginating a bounded range now returns the expected results, so a query written against the earlier behavior may return different results after upgrading. ::: ## Aggregate Queries @@ -174,12 +201,12 @@ For indices composed of multiple fields ([example from the DPNS data contract](h The [getDocuments](../reference/dapi-endpoints-platform-endpoints.md#getdocuments) v1 surface adds an aggregate-query mode. The same `where` / `orderBy` clauses described above still apply; an additional `select` projection (and optional `groupBy`) determines whether the request returns documents or aggregate values over the matched set. -| `select` | Returns | -| ---------------- | ------- | -| `DOCUMENTS` | Matched documents (same as v0). | -| `COUNT(*)` | Number of documents matching the query. | -| `SUM()` | Sum of `` across matching documents. | -| `AVG()` | `(count, sum)` pair the client divides to compute the average. | +| `select` | Returns | +| - | - | +| `DOCUMENTS` | Matched documents (same as v0). | +| `COUNT(*)` | Number of documents matching the query. | +| `SUM()` | Sum of `` across matching documents. | +| `AVG()` | `(count, sum)` pair the client divides to compute the average. | `groupBy` is optional. With an empty `groupBy`, the response carries a single aggregate value; with a `groupBy` of one or two fields, the response carries one entry per group. @@ -187,10 +214,43 @@ Aggregate queries impose extra schema requirements on the document type — `COU `SUM` / `AVG` integer values are returned as JS strings so JavaScript clients don't lose precision on values larger than `Number.MAX_SAFE_INTEGER`. -:::{note} -`HAVING`, `OFFSET`, `COUNT()`, `MIN`, `MAX`, and multi-projection `SELECT` are present on the wire but currently return `Unsupported`. Callers can encode them in builders ahead of server support landing, but evaluation rejects them today. +### Aggregate query limits + +The `limit` modifier behaves differently in aggregate result modes than it does when returning `DOCUMENTS`, and some `select` × `groupBy` combinations reject it outright. On the wire, [`limit` is an optional field](https://github.com/dashpay/platform/blob/v4.1.0/packages/dapi-grpc/protos/platform/v0/platform.proto#L958-L1002): + +- Omit `limit` to request the server's default. +- Send a positive value to request an explicit cap. +- In aggregate result modes, `limit: 0` is rejected with `InvalidLimit`. When returning `DOCUMENTS`, `0` uses the configured default as described under [Query Modifiers](#query-modifiers). + +SDK bindings that must pass a numeric argument use `-1` as the server-default sentinel; any other negative value is rejected. + +:::{versionchanged} 4.1.0 +In aggregate result modes, an effective limit of zero is now rejected with `InvalidLimit` rather than walking storage with a zero bound, which previously surfaced as an empty result set. ::: +How a positive `limit` is interpreted depends on `groupBy`: + +| `select` / `groupBy` | Effect of `limit` | +| - | - | +| `DOCUMENTS` | Uses the general behavior described under [Query Modifiers](#query-modifiers). | +| `COUNT` with an empty `groupBy` | Rejected with `InvalidLimit`. An aggregate count is a single row by construction. | +| `COUNT` grouped by an `In` field | Rejected with `InvalidLimit`. The `In` array is already capped at 100 entries, so the result is bounded. Narrow the `In` array instead. | +| `COUNT` grouped by a range field | Caps the distinct-range walk, so the response carries at most `limit` groups. | +| `COUNT` grouped by an `In` field and a range field | A global cap over the emitted stream, not a per-branch cap. With three `In` values and `limit: 5`, the response carries at most 5 entries in total across all branches. | + +`SUM` and `AVG` follow the same policy as `COUNT`: distinct walks apply the default/cap/reject-zero rules, and a zero limit is rejected. + +#### Oversized limits with and without proofs + +On range-grouped aggregates, an oversized `limit` is handled differently depending on whether a proof is requested. With `prove: true`, a `limit` above the node's configured maximum is rejected with `InvalidLimit` so that proof bytes stay deterministic. With `prove: false`, the limit is silently clamped to that maximum instead. With the default maximum of 100, for example, a caller requesting 500 groups receives at most 100 with no error, which can look like missing data. + +Compound carrier-aggregate shapes that pair an `In` field with a range field and request a proof cap the outer range walk at [10 entries](https://github.com/dashpay/platform/blob/v4.1.0/packages/rs-drive/src/query/drive_document_count_query/mod.rs#L127). This is a hard ceiling: a `limit` above it is rejected, and callers needing more results issue repeated queries over disjoint outer-range windows. + +### Other aggregate restrictions + +- `startAt` and `startAfter` are supported only with `DOCUMENTS`. Aggregate result modes reject cursors; narrow the `where` range to query a different group range. +- `HAVING`, `OFFSET`, `COUNT()`, `MIN`, `MAX`, and multi-projection `SELECT` are present on the wire but currently return `Unsupported`. Callers can encode them in builders ahead of server support landing, but evaluation rejects them today. + ## Example query The following query combines both a where clause and query modifiers. @@ -238,4 +298,39 @@ for (const [id, doc] of results) { } ``` ::: + +:::{tab-item} Evo SDK aggregate example +The Evo SDK does not expose `select` directly. Each aggregate mode has its own method — `documents.count()`, `documents.sum(query, property)`, and `documents.average(query, property)`. `groupBy` is passed as part of the query. + +```javascript +import { EvoSDK } from '@dashevo/evo-sdk'; + +const sdk = EvoSDK.testnetTrusted(); +await sdk.connect(); + +// COUNT grouped by a range field: one entry per distinct rating. +// The `rating` range clause is what puts the query in grouped mode. +const counts = await sdk.documents.count({ + dataContractId: 'BdgTqaTAPYMyhp1WdeWdcvYSgoD7AuJ7tVCaCSXyQgyP', + documentTypeName: 'review', + where: [ + ['resourceId', '==', 'dashnote'], + ['rating', 'between', [1, 5]], + ], + orderBy: [ + ['rating', 'asc'], + ], + groupBy: ['rating'], +}); + +// Keys are hex-encoded index keys, not the raw field values, and +// counts are BigInt. A small positive integer encodes as `0x80 | value`, +// so rating 5 is the key "85". +for (const [key, count] of counts) { + console.log(`${key - 80} stars: ${count.toString()} review(s)`); +} +``` + +Both the document type's schema flags and the query's index must support the aggregate — this example needs `documentsCountable` plus `rangeCountable`, and a `[resourceId, rating]` index. An ungrouped `count()` returns a single-entry map keyed by the empty string, so read it with `counts.values().next().value`. +::: :::: diff --git a/docs/resources/faq.md b/docs/resources/faq.md index 1f3b0fa72..be4c6d53f 100644 --- a/docs/resources/faq.md +++ b/docs/resources/faq.md @@ -159,7 +159,10 @@ identity and votes to lock the name, the identity receives the name. :::{dropdown} Can usernames be transferred? -Currently, usernames are non-transferrable. Future updates may enable transfers. +Yes. Since Dash Platform v4.1, a username can be transferred to another identity, or listed for sale +and purchased by another identity. After a transfer or sale, the name resolves to its new owner. The +name record itself remains immutable and permanent - it cannot be edited or deleted, only transferred +or sold. See [Name transfers and sales](../explanations/dpns.md#name-transfers-and-sales) for details. ::: diff --git a/docs/tutorials/building-platform.md b/docs/tutorials/building-platform.md index d01215c4b..e44a9b434 100644 --- a/docs/tutorials/building-platform.md +++ b/docs/tutorials/building-platform.md @@ -35,7 +35,7 @@ nvm install 20.18 ### Docker :::{warning} -Only complete the following steps if you do not already have Docker installed. Otherwise, just make sure you have a version that meets the requirements in the [Platform repository README](https://github.com/dashpay/platform?tab=readme-ov-file#how-to-build-and-set-up-a-node-from-the-code-in-this-repo). +Only complete the following steps if you do not already have Docker installed. Otherwise, just make sure you have a version that meets the requirements in the [Platform book's Getting Started section](https://github.com/dashpay/platform/blob/master/book/src/getting-started.md). ::: ``` shell @@ -54,7 +54,7 @@ newgrp docker ### Protocol buffers ``` shell -wget https://github.com/protocolbuffers/protobuf/releases/download/v27.3/protoc-27.3-linux-x86_64.zip +wget https://github.com/protocolbuffers/protobuf/releases/download/v32.0/protoc-32.0-linux-x86_64.zip sudo unzip protoc-*-linux-x86_64.zip -d /usr/local ``` @@ -65,15 +65,19 @@ Execute the following script to install Rust. Use the default options during the ``` shell curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh . "$HOME/.cargo/env" -rustup default 1.85.0 +rustup default 1.92 ``` ### WASM CLI ``` shell -cargo install wasm-bindgen-cli@0.2.100 +cargo install wasm-bindgen-cli@0.2.108 ``` +:::{note} +The `wasm-bindgen-cli` version must match the `wasm-bindgen` version in the platform repository's `Cargo.lock`, or the build will stop at a version check. Confirm the required version with `grep 'name = "wasm-bindgen"' -A1 Cargo.lock`. +::: + ### Check versions Run the following commands to see what version of each package is installed: diff --git a/docs/tutorials/connecting-to-testnet.md b/docs/tutorials/connecting-to-testnet.md index 6074bcf30..4fa78d6ed 100644 --- a/docs/tutorials/connecting-to-testnet.md +++ b/docs/tutorials/connecting-to-testnet.md @@ -51,7 +51,7 @@ Once this returns successfully, you're ready to begin developing! See the [Quick ## Connect to a Local Devnet -The SDK supports connecting to a local development network managed by [dashmate](https://github.com/dashpay/platform/tree/master/packages/dashmate). The `local` factory methods expect a dashmate-managed environment with a quorum sidecar running at `127.0.0.1:2444`. +The SDK supports connecting to a local development network managed by [dashmate](https://github.com/dashpay/platform/tree/master/packages/dashmate). The `local` factory methods expect a dashmate-managed environment with a quorum sidecar running at `127.0.0.1:22444`. ```{code-block} javascript :caption: localConnect.mjs diff --git a/docs/tutorials/contracts-and-documents/retrieve-data-contract-history.md b/docs/tutorials/contracts-and-documents/retrieve-data-contract-history.md index d3824afcf..c5918c5c2 100644 --- a/docs/tutorials/contracts-and-documents/retrieve-data-contract-history.md +++ b/docs/tutorials/contracts-and-documents/retrieve-data-contract-history.md @@ -9,6 +9,13 @@ Contract tutorial](../../tutorials/contracts-and-documents/register-a-data-contr contracts that have enabled the `keepsHistory` option during contract creation will store revision information. +:::{note} +This retrieves revisions of the contract definition. It does not return the revision history of +individual documents (see [`getDocumentHistory`](../../reference/dapi-endpoints-platform-endpoints.md#getdocumenthistory)) +or records of document transfers and sales (see [document ownership and pricing +history](../../reference/glossary.md#history-document-ownership-and-pricing)). +::: + ## Prerequisites * [General prerequisites](../../tutorials/introduction.md#prerequisites) (Node.js / Dash SDK installed) diff --git a/docs/tutorials/example-apps/dashnote.md b/docs/tutorials/example-apps/dashnote.md index 19884fe1c..ce26db03a 100644 --- a/docs/tutorials/example-apps/dashnote.md +++ b/docs/tutorials/example-apps/dashnote.md @@ -262,7 +262,6 @@ Each operation file is intentionally small. The app-level pattern is: validate i * SDK method: sdk.documents.create({ document, identityKey, signer }) */ import type { Logger } from "../lib/logger"; -import { PLATFORM_VERSION_OVERRIDE } from "../../../../platformVersion.mjs"; import { loadSdkModule } from "./sdkModule"; import type { DashKeyManager, DashSdk } from "./types"; @@ -305,7 +304,7 @@ export async function createNote({ const json = typeof document.toJSON === "function" - ? (document.toJSON(PLATFORM_VERSION_OVERRIDE) as Record) + ? (document.toJSON(sdk.version()) as Record) : {}; const noteId = String(json.$id ?? json.id ?? ""); if (!noteId) { diff --git a/docs/tutorials/node-setup/connect-to-a-network-dash-core-full-node.md b/docs/tutorials/node-setup/connect-to-a-network-dash-core-full-node.md index 8db9f5a4c..7206f6681 100644 --- a/docs/tutorials/node-setup/connect-to-a-network-dash-core-full-node.md +++ b/docs/tutorials/node-setup/connect-to-a-network-dash-core-full-node.md @@ -8,7 +8,7 @@ Since Dash Platform is fully accessible via DAPI, running a full node is unneces ## Config File - The config file shown below may be used to connect a Dash Core node to Testnet. Testnet currently operates using [Dash Core v19.3.0](https://github.com/dashpay/dash/releases/tag/v19.3.0). + The config file shown below may be used to connect a Dash Core node to Testnet. ```ini dash-testnet.conf # dash-testnet.conf diff --git a/docs/tutorials/node-setup/connect-to-a-network-dash-masternode.md b/docs/tutorials/node-setup/connect-to-a-network-dash-masternode.md index 8d007fe21..e68f8c763 100644 --- a/docs/tutorials/node-setup/connect-to-a-network-dash-masternode.md +++ b/docs/tutorials/node-setup/connect-to-a-network-dash-masternode.md @@ -116,23 +116,25 @@ Example output of `dashmate wallet mint 10 --address=yYqfdpePzn2kWtMxr9nz22HBFM7 Once the address is funded, you can begin creating identities, data contracts, etc. and experimenting with Dash Platform. The [other tutorials](../../tutorials/introduction.md) in this section will help you get started. -To make the Dash SDK connect to your local network, set the `network` option to `'local'`: +To make the Dash SDK connect to your local network, use the `localTrusted()` factory method: ```javascript -const clientOpts = { - network: 'local', - ... -}; +import { EvoSDK } from '@dashevo/evo-sdk'; -const client = new Dash.Client(clientOpts); +const sdk = EvoSDK.localTrusted(); +await sdk.connect(); ``` +See [Connect to a Local Devnet](../connecting-to-testnet.md#connect-to-a-local-devnet) for more detail. + ## Testnet Masternode Setup :::{important} Running a masternode requires familiarity with Dash Platform services. Improper configuration may impact testing so please exercise caution if running a masternode. ::: +When upgrading an existing node, check the [platform release notes](https://github.com/dashpay/platform/releases) for per-release upgrade steps and breaking changes. + To setup a testnet masternode, please refer to the comprehensive documentation of the process as described [here](https://docs.dash.org/en/stable/masternodes/setup-testnet.html#dashmate-installation). The following video also details how to complete the process. ```{eval-rst} diff --git a/docs/tutorials/setup-sdk-client.md b/docs/tutorials/setup-sdk-client.md index b01d38591..f4ff350d8 100644 --- a/docs/tutorials/setup-sdk-client.md +++ b/docs/tutorials/setup-sdk-client.md @@ -60,7 +60,6 @@ import { SecurityLevel, wallet, } from '@dashevo/evo-sdk'; -import { PLATFORM_VERSION_OVERRIDE } from './platformVersion.mjs'; /** @typedef {import('@dashevo/evo-sdk').Identity} Identity */ /** @typedef {import('@dashevo/evo-sdk').IdentityPublicKey} IdentityPublicKey */ @@ -138,21 +137,25 @@ export async function dip13KeyPath(network, identityIndex, keyIndex) { // SDK client helpers // --------------------------------------------------------------------------- -export { PLATFORM_VERSION_OVERRIDE }; - /** * Create and connect an EvoSDK client for the selected network. * + * The platform protocol version is deliberately left unset so the SDK + * negotiates it with the network: it starts from a conservative version and + * ratchets up to whatever the network reports, capped at the newest version + * the SDK itself understands. Pinning it via the `version` option disables + * that negotiation outright, so a hardcoded value silently goes stale the + * next time the network upgrades. Use `sdk.version()` when you need the + * negotiated value. + * * @param {string} [network='testnet'] * @returns {Promise} */ export async function createClient(network = 'testnet') { const factories = /** @type {Record EvoSDK>} */ ({ - testnet: () => - EvoSDK.testnetTrusted({ version: PLATFORM_VERSION_OVERRIDE }), - mainnet: () => - EvoSDK.mainnetTrusted({ version: PLATFORM_VERSION_OVERRIDE }), - local: () => EvoSDK.localTrusted({ version: PLATFORM_VERSION_OVERRIDE }), + testnet: () => EvoSDK.testnetTrusted(), + mainnet: () => EvoSDK.mainnetTrusted(), + local: () => EvoSDK.localTrusted(), }); const factory = factories[network];