Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion book/src/data-model/documents.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ From protocol version 14 a reference to a document ID means that one document or

The ID of a new document only exists once the nonce of its create transition is assigned, and it changes if the transition is rebuilt with another nonce:
- The ID a `Document` carries before its create transition is built (for example the one `create_document_from_data` gives it) is a **placeholder**. `DocumentCreateTransitionV0::from_document` replaces it with the derived ID, so every transition built through dpp carries the right one.
- Read the ID from the transition, or from the confirmed document `put_to_platform_and_wait_for_response` returns, not from the document you passed in.
- On the Rust path (rs-sdk, or `from_document` directly) the `Document` you passed in keeps its placeholder: read the ID from the transition, or from the confirmed document `put_to_platform_and_wait_for_response` returns.
- To know IDs up front (a chain of documents that reference each other), assign the nonces first: nonces may be used out of order within a window of 24.
- JavaScript gets the same through `wasm-dpp2`, with one difference: `new DocumentCreateTransition({ document, identityContractNonce })` derives the ID for the network's protocol version (`platformVersion` option, latest by default) and writes it both onto the transition and back onto `document`, so after construction `document.id` is the final ID and may be read from there. `Document.generateId(type, owner, contract, entropy, identityContractNonce)` and `document.setIdForCreation(identityContractNonce)` give the ID before the transition exists, and `new Document({ ..., identityContractNonce })` derives it at construction (an explicit `id` passed alongside the nonce must equal the derived one). A `Document` built without a nonce carries the entropy-only placeholder until it is passed to `DocumentCreateTransition`. No app needs to reimplement the hash.

## The Accessor Traits

Expand Down
10 changes: 10 additions & 0 deletions book/src/sdk/put-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ so the SDK switches derivation when the network does. Because the ID depends on
nonce, the ID on the document you pass in is a placeholder: use the ID of the confirmed
document that `put_to_platform_and_wait_for_response` returns.

The JavaScript SDK follows the same pipeline. `sdk.documents.create` goes through
`put_to_platform_and_wait_for_response` and hands the confirmed document back. An app
that builds the transition itself (to sign it separately or cache the signed bytes)
gets the derivation from `wasm-dpp2`: `new DocumentCreateTransition({ document,
identityContractNonce })` derives the ID from the document's entropy and the nonce for
the network's protocol version (`platformVersion` option, latest by default), writes it
onto the transition and back onto `document`, and the transition is then batched, signed
and broadcast as before. The IDs such a transition carries are final; nothing has to be
hashed on the app side.

### Step 3: Validate Structure

Before broadcasting, the SDK validates the transition's basic structure:
Expand Down
17 changes: 17 additions & 0 deletions packages/js-evo-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Evo SDK provides a high-level, strongly-typed interface for interacting with [Da
- [Facades](#facades)
- [Ranked queries](#ranked-queries)
- [Document references (`refersTo`)](#document-references-refersto)
- [Building a document create transition by hand](#building-a-document-create-transition-by-hand)
- [Immutable properties (`immutable`)](#immutable-properties-immutable)
- [Chained queries (provable semi-join)](#chained-queries-provable-semi-join)
- [Composite queries (a page plus its sub-queries)](#composite-queries-a-page-plus-its-sub-queries)
Expand Down Expand Up @@ -224,6 +225,22 @@ try {
}
```

## Building a document create transition by hand

`sdk.documents.create` fetches the nonce, builds, signs, broadcasts and returns the confirmed document, whose `id` is the one Platform stored. An app that needs the signed transition itself (to broadcast later, or to cache the signed bytes) builds it from the re-exported `wasm-dpp2` classes:

```ts
import { Document, DocumentCreateTransition, BatchTransition } from '@dashevo/evo-sdk';

const document = new Document({ properties, documentTypeName, dataContractId, ownerId });
const transition = new DocumentCreateTransition({ document, identityContractNonce: nonce });
const batch = BatchTransition.fromBatchedTransitions([transition.toDocumentTransition()], ownerId, 0); // userFeeIncrease
const stateTransition = batch.toStateTransition();
// sign, then sdk.stateTransitions.broadcast(stateTransition)
```

From protocol version 14 the id of a new document commits to the identity contract nonce of its create transition. `new DocumentCreateTransition(...)` derives that id from the document's entropy and `identityContractNonce`, puts it on the transition and writes it back onto `document`, so `document.id` is final once the transition exists and equals `transition.base.id`. Before that the `Document` carries a placeholder. To know the id earlier, `document.setIdForCreation(nonce)` or `Document.generateId(type, owner, contract, entropy, nonce)`, or pass `identityContractNonce` to the `Document` constructor. Pass `platformVersion` (defaults to latest) to any of them for a network on an earlier protocol version. No app needs to reimplement the hash.

## Immutable properties (`immutable`)

From protocol version 14 a mutable document type can freeze some of its top-level properties at creation with the doctype-level `immutable` list, while the rest of the document stays replaceable. A second list, `immutableAllowSetting`, names the frozen properties a replace may still set while the stored document has no value for them; once present they are frozen too. Both are consensus-enforced on every replace, and a fetched contract can be asked what it declares:
Expand Down
9 changes: 8 additions & 1 deletion packages/rs-platform-version/src/version/v14.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,14 @@ pub const PROTOCOL_VERSION_14: ProtocolVersion = 14;
/// Ids of documents created before the upgrade can not be produced by
/// the new derivation either. A client that still derives the entropy
/// only id has every create rejected with
/// `InvalidDocumentTransitionIdError`.
/// `InvalidDocumentTransitionIdError`. Every create path of the clients
/// in this repository derives through `Document::generate_document_id`:
/// `DocumentCreateTransitionV0::from_document` for dpp, rs-sdk and the
/// bindings built on them, and in wasm-dpp2 the `DocumentCreateTransition`
/// constructor (which also writes the id back onto the JavaScript
/// `Document`), `Document.generateId` with its `identityContractNonce`
/// argument, `setIdForCreation` and the `identityContractNonce`
/// constructor option.
/// 19. **Document deletion by moderators**: a document type of a contract
/// that declares moderation may set `canBeDeletedByModerators` (meta-schema
/// v3, fixed when the type is created, refused on a type that keeps
Expand Down
35 changes: 35 additions & 0 deletions packages/wasm-dpp2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,38 @@ Internal build of the Dash Platform Protocol v2 WebAssembly bindings.

The build scripts defer to `packages/scripts/build-wasm.sh` to keep behaviour
consistent with other WASM packages such as `@dashevo/wasm-sdk`.

## Document ids

From protocol version 14 the id of a new document commits to the identity
contract nonce of its create transition (see the book, *Data Model →
Documents → Document ID Generation*), so a `Document` built with
`new Document({...})` and no `identityContractNonce` carries a **placeholder**
id: the entropy-only derivation of earlier versions, which consensus no longer
accepts.

The id becomes final where the nonce is known, and the bindings derive it for
you:

```ts
const document = new Document({ properties, documentTypeName, dataContractId, ownerId });

// Derives the id from the document's entropy and the nonce, writes it onto
// the transition and back onto `document`: document.id equals transition.base.id.
const transition = new DocumentCreateTransition({ document, identityContractNonce: nonce });

// To know the id before the transition exists (another document in the same
// batch references it):
document.setIdForCreation(nonce);
// or derive it without a Document:
const idBytes = Document.generateId(documentTypeName, ownerId, dataContractId, entropy, nonce);
// or build the document with its final id from the start:
const ready = new Document({ properties, documentTypeName, dataContractId, ownerId, identityContractNonce: nonce });
```

Each of these takes an optional `platformVersion` (latest by default); before
protocol version 14 the derivation ignores the nonce. Whatever id a `Document`
carried before it is passed to `DocumentCreateTransition` is replaced: the
transition can only carry the id consensus recomputes. For the same reason
`new Document({...})` refuses an explicit `id` that disagrees with the one its
`identityContractNonce` derives. No app needs to reimplement the hash.
Loading
Loading