Skip to content

Latest commit

 

History

History
436 lines (353 loc) · 24.2 KB

File metadata and controls

436 lines (353 loc) · 24.2 KB

Contract Documents

Contract Document Overview

The documents object defines each type of document in the data contract. At a minimum, a document must consist of 1 or more properties. The additionalProperties properties keyword must be included as described in the constraints section and each property must be assigned a position.

:::{note} The $schema property is required for each document type but is automatically injected by the platform during contract enrichment. Do not include it in user-submitted document type definitions — providing it will result in a validation error. :::

The following example shows a minimal documents object defining a single document (note) with one property (message).

{
  "note": {
    "type": "object",
    "properties": {
      "message": {
        "type": "string",
        "position": 0
      }
    },
    "additionalProperties": false
  }
}

Documents may also define indices, a list of required or transient properties, and a custom configuration. Refer to this table for a brief description of the major document sections:

Feature Description
Configuration Document-level settings affecting behavior such as mutability, deletion, and transferability
Properties Definitions and constraints for each field within a document
Indices Definitions for indexing document fields to support efficient querying

Document Properties

The properties object defines each field that a document will use. Each field consists of an object that, at a minimum, must define its data type (string, number, integer, boolean, array, object).

Fields may also apply a variety of optional JSON Schema constraints related to the format, range, length, etc. of the data. A full explanation of JSON Schema capabilities is beyond the scope of this document. For more information regarding its data types and the constraints that can be applied, please refer to the JSON Schema reference documentation.

Assigning Position

Each property in a level must be assigned a unique position value, with ordering starting at zero and incrementing with each property. When using nested objects, position counting resets to zero for each level. This structure supports backward compatibility in data contracts by ensuring consistent ordering for serialization and deserialization processes.

Object Properties

The object type cannot be an empty object but must have one or more defined properties. For example, the body property shown below is an object containing a single string property (objectProperty):

const contractDocuments = {
  message: {
    type: "object",
    properties: {
      body: {
        type: "object",
        position: 0,
        properties: {
          objectProperty: {
            type: "string",
            "position": 0
          },
        },
        additionalProperties: false,
      },
      header: {
        type: "string",
        "position": 1
      }
    },
    additionalProperties: false
  }
};

Required Properties

Each document may have some fields that are required for the document to be valid and other fields that are optional. Required fields are defined via the required array, which consists of a list of the field names from the document that must be present. Exclude the required object for documents without required properties.

"required": [
  "<field name a>",
  "<field name b>"
]

Example
The following example (excerpt from the DPNS contract's domain document) demonstrates a document with required fields:

"required": [
  "$createdAt",
  "$updatedAt",
  "$transferredAt",
  "label",
  "normalizedLabel",
  "normalizedParentDomainName",
  "preorderSalt",
  "records",
  "subdomainRules"
]

Transient Properties

Each document may have transient fields that require validation but do not need to be stored by the system once validated. Transient fields are defined in the transient array. Only include the transient object for documents with at least one transient property.

Example

The following example (from the DPNS contract's domain document) demonstrates a document that has 1 transient field:

    "transient": [
      "preorderSalt"
    ]

Property Constraints

There are a variety of constraints currently defined for performance and security reasons.

Description Value
Minimum number of properties 1
Maximum number of properties 100
Minimum property name length 1
Maximum property name length 64
Property name characters Alphanumeric (A-Z, a-z, 0-9)
Hyphen (-)
Underscore (_)

Document Indices

Document indices may be defined if indexing on document fields is required. The indices object should only be included for documents with at least one index.

The indices array consists of one or more objects that each contain:

  • A unique name for the index

  • A properties array composed of a <field name: sort order> object for each document field that is part of the index (only asc is currently supported)

    :::{admonition} Compound Indices :class: attention When defining an index with multiple properties, the ordering of properties is important. Refer to the mongoDB documentation for details. Dash uses GroveDB, which works similarly but requires listing all the index's fields in query order by statements. :::

  • An optional unique element that determines if duplicate values are allowed for the document

  • An optional nullSearchable element that indicates whether the index allows searching for NULL values. If nullSearchable is false (default: true) and all properties of the index are null then no reference is added.

  • An optional contested element that determines if duplicate values are allowed for the document

:::{code-block} json :force:

"indices": [ { "name": "", "properties": [ { "": "asc" }, { "": "asc" } ], "unique": true|false, "nullSearchable": true|false, "contested": { "fieldMatches": [ { "field": "", "regexPattern": "" } ], "resolution": 0 } }, { "name": "", "properties": [ { "": "asc" }, ], } ] :::

Contested Indices

Contested unique indices provide a way for multiple identities to compete for ownership when a new document field matches a predefined pattern. This system enables fair distribution of valuable documents, such as premium DPNS names, through community-driven decision-making.

A two week contest begins when a match occurs. For the first week, additional contenders can join by paying a fee of 0.2 Dash. During this period, masternodes and evonodes vote on the outcome. The contest can result in the awarding of the document to the winner, a locked vote where no document is awarded, or potentially a restart of the contest if specific conditions are met.

The table below describes the properties used to configure a contested index:

Property Name Type Description
fieldMatches array Array containing conditions to check
fieldMatches.field string Name of the field to check for matches
fieldMatches.regexPattern string Regex used to check for matches
resolution integer Method to resolve the contest:
0 - masternode voting

Example

This example (from the DPNS contract's domain document) demonstrates the use of a contested index:

"contested": {
  "fieldMatches": [
    {
      "field": "normalizedLabel",
      "regexPattern": "^[a-zA-Z01-]{3,19}$"
    }
  ],
  "resolution": 0,
  "description": "If the normalized label part of this index is less than 20 characters (all alphabet a-z, A-Z, 0, 1, and -) then a masternode vote contest takes place to give out the name"
}

Index Constraints

For performance and security reasons, indices have the following constraints. These constraints are subject to change over time.

Description Value
Minimum/maximum length of index name 1 / 32
Maximum number of indices 10
Maximum number of unique indices 10
Maximum number of contested indices 1
Maximum number of properties in a single index 10
Maximum length of indexed string property 63
Usage of $id in an index disallowed N/A
Note: Dash Platform does not allow indices for arrays.
Maximum length of indexed byte array property
255
Note: Dash Platform does not allow indices for arrays.
Maximum number of indexed array items
1024

:::{seealso} For all protocol constants, see Protocol Constants. :::

Example
The following example (excerpt from the DPNS contract's preorder document) creates an index named saltedHash on the saltedDomainHash property that also enforces uniqueness across all documents of that type:

"indices": [
  {
    "name": "saltedHash",
    "properties": [
      {
        "saltedDomainHash": "asc"
      }
    ],
    "unique": true
  }
]

Document Configuration

Documents support the following configuration options to provide flexibility in contract design. Only include configuration options in a data contract when using non-default values.

Document option Type Description
documentsKeepHistory boolean If true, documents keep a history of all changes. Default: false.
documentsMutable boolean If true, documents are mutable. Default: true.
canBeDeleted boolean If true, documents can be deleted. Default: true.
transferable integer Transferable without a marketplace sell:
0 - Never
1 - Always
See the NFT page 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 for more details
creationRestrictionMode integer Restriction of document creation:
0 - No restrictions
1 - Contract owner only
2 - No Creation Allowed
See the NFT page for more details
keywords array of strings Up to 20 strings (3–50 characters each) describing the document type for searchability
Security option Type Description
requiresIdentity
EncryptionBoundedKey
integer Key requirements for identity encryption:
0 - Unique non-replaceable
1 - Multiple
2 - Multiple with reference to latest key
requiresIdentity
DecryptionBoundedKey
integer Key requirements for identity decryption:
0 - Unique non-replaceable
1 - Multiple
2 - Multiple with reference to latest key
signatureSecurity
LevelRequirement
integer Public key security level:
1 - Critical
2 - High
3 - Medium. Default is High if none specified.

Token Costs

The tokenCost option allows document types to require token payment for operations. When configured, users must pay a specified amount of tokens to perform each operation type. Each operation cost is defined as a documentActionTokenCost object with the following properties:

Property Type Required Description
contractId array (32 bytes) No Identifier of the contract containing the payment token. Defaults to the current contract if omitted.
tokenPosition integer (0–65535) Yes Position of the token within the contract
amount integer (1–281474976710655) Yes Number of tokens required for the operation
effect integer No Token disposition after payment:
0 - Transfer to contract owner (default)
1 - Burn (tokens destroyed)
gasFeesPaidBy integer No Who pays gas fees for the operation:
0 - Document owner (default)
1 - Contract owner
2 - Prefer contract owner (falls back to document owner if insufficient)

The following operation types can each have an independent cost configuration:

Operation Description
create Creating a new document
replace Replacing an existing document
delete Deleting a document
transfer Transferring document ownership
update_price Updating a document's purchase price
purchase Purchasing a document

:::{dropdown} List of all usable document properties

This list of properties is defined in the Rust DPP implementation and the document meta-schema.

Property Name Type Description
type string Specifies the type of the document, constrained to "object".
$schema string Platform-injected during enrichment; not accepted in user submissions.
$defs object References the documentProperties definition.
indices array Defines indices for the document with properties like name, unique, nullSearchable, and contested.
signatureSecurity
LevelRequirement
integer Public key security level:
1 - Critical
2 - High
3 - Medium. Default is High if none specified.
documentsKeepHistory boolean If true, documents keep a history of all changes. Default: false.
documentsMutable boolean If true, documents are mutable. Default: true.
canBeDeleted boolean If true, documents can be deleted. Default: true.
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.
requiresIdentity
EncryptionBoundedKey
integer Key requirements for identity encryption:
0 - Unique non-replaceable
1 - Multiple
2 - Multiple with reference to latest key
requiresIdentity
DecryptionBoundedKey
integer Key requirements for identity decryption:
0 - Unique non-replaceable
1 - Multiple
2 - Multiple with reference to latest key
properties object Defines the properties of the document.
transient array An array of strings specifying transient properties that are validated by Platform but not stored.
tokenCost object Defines token costs for document operations (create, replace, update_price, delete, transfer, purchase)
keywords array Up to 20 strings (3–50 characters each) for searchability
additionalProperties boolean Specifies whether additional properties are allowed. Must be set to false, meaning no additional properties are allowed beyond those defined.

:::

Example

The following example (from the DPNS contract's domain document) demonstrates the use of several configuration options:

{
  "domain": {
    "documentsMutable": false,
    "canBeDeleted": true,
    "transferable": 1,
    "tradeMode": 1,
    "..."
  }
}

Aggregate Query Flags

:::{versionadded} 3.1.0 :::

Document types can opt into aggregate query support (count / sum / average) by setting flags at the document-type level. These flags control the underlying storage layout — once set on a published contract they cannot be changed by a contract update.

There are two axes:

  • Doctype-wide (documents*) — applies the aggregate over the entire document type. Set at the document type root, alongside other doctype options like documentsKeepHistory.
  • Per-index range (range*) — extends the corresponding aggregate to range queries on indexed properties. Set on the index's property entry. Requires the matching base flag.
Flag Type Purpose Required for
documentsCountable Boolean Doctype-wide counts (empty where or ==/IN clauses on indexed fields). SELECT COUNT(*) without a range clause.
rangeCountable Boolean Per-index counts over a range. Requires documentsCountable. SELECT COUNT(*) with a range clause or GROUP BY <range_field>.
documentsSummable String Doctype-wide sums of the named integer property. SELECT SUM(<that property>).
rangeSummable Boolean Per-index sums over a range. Requires documentsSummable. SELECT SUM(<field>) with a range clause.
documentsAverageable String Syntactic sugar for documentsCountable: true + documentsSummable: "<prop>". SELECT AVG(<that property>).
rangeAverageable Boolean Syntactic sugar for rangeCountable: true + rangeSummable: true. Requires documentsAverageable. SELECT AVG(<field>) with a range clause.

The averageable flags desugar to the underlying count + sum flags during contract parsing — same on-disk layout — so authors who think in terms of averages get a single flag and downstream code paths (insert, query, estimation) stay unchanged. If both documentsAverageable and documentsSummable are set, they must name the same property.

These flags are validated against the v1 document meta-schema and are rejected when applied to pre-v12 contracts. The full v1 meta-schema, including these flags, is defined in rs-dpp.

See the getDocuments reference for the request/response shapes that consume these flags.

Keyword Constraints

There are a variety of keyword constraints currently defined for performance and security reasons. The following constraints apply to document definitions. Unless otherwise noted, these constraints are defined in the platform's JSON Schema rules (e.g., rs-dpp document meta schema).

Keyword Constraint
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: <something> maxLength must be defined (maximum: 50000)
format: <something> maxLength must be defined (maximum: 50000)
$ref: <something> Disabled
$ref can only reference $defs. Remote references not supported.
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
patternProperties Restricted - cannot be used for data contracts
pattern Accept only RE2 compatible regular expressions (defined in DPP logic)

Example Syntax

This example syntax shows the structure of a documents object that defines two documents, an index, and a required field.

:::{code-block} json :force:

{ "": { "type": "object", "properties": { "": { "type": "", "position": "" }, "": { "type": "", "position": "" }, }, "indices": [ { "name": "", "properties": [ { "": "asc" } ], "unique": true|false }, ], "required": [ "" ], "additionalProperties": false }, "": { "type": "object", "properties": { "": { "type": "", "position": "" }, "": { "type": "", "position": "" }, }, "additionalProperties": false },
} :::

Document Schema

See full document schema details in the rs-dpp document meta schema.