Dash Platform Data Contracts
Everyone in Web3 already knows of smart contracts, the groundbreaking innovation of Ethereum that popularized the concept of a dapp. However, few are aware of Dash Platform’s new supplement to smart contracts that will make dapp development more accessible to the masses: data contracts.
Data contracts are a powerful tool already used widely across the Web2 data services landscape due to their many benefits to user and developer experience. They’re relatively simple JSON schemas that define the structures of data a dapp can store. Utilizing them in Dash Platform allows us to take advantage of their traditional benefits while also enabling Web2 developers to store their app data on a decentralized Web3 platform without needing to learn a smart contract language like Solidity. Rather, they can easily do so just by using constructs they’re already familiar with.
In addition to greater accessibility and smoother user experience, data contracts also enable a variety of other useful features, such as easy indexing, versioning, and built-in documentation. Ultimately, they will assist in the cultivation of a diverse ecosystem of Dash-based dapps, and more widespread adoption for crypto as a whole.
This article accompanies the release of dashpay.io, a web app where users can automatically generate a data contract based on descriptions of their intended dapp using AI. We will begin by walking through the high-level architecture and applications of data contracts before going back and diving deeper into the architecture details.
Application
At a high level, a Dash Platform data contract is a JSON schema that defines the structures of the data a dapp will store. It defines the allowed properties, such as “city” or “cuisine” for a restaurant dapp, the validation logic, such as the “maxLength” of a string property, and the indexes created on the properties. Developers must submit their data contracts to Platform for system-level validation before the users of their dapps may submit documents to their data contracts for dapp-level validation. This ensures that the dapp data will play nicely with the rest of the system while giving developers control over the structure and types of data that can be submitted to their dapps. Data contracts are therefore useful for a number of reasons beyond just enabling an easy transition from Web2 to Web3:
- Interoperability. First and foremost, data contracts enable the validations that ensure smooth interoperability between user data, dapps, and the underlying platform, ultimately resulting in better user and developer experience. Also, by standardizing the way data is stored in Dash Platform, other platforms can easily gain interoperability in the future by adopting the same format.
- Simplicity. All data contracts in Dash Platform follow the same general guidelines and format, and are very easy to understand compared to smart contracts. Once you gain an initial understanding of them, figuring out how to interact with another developer’s dapp or creating a new data contract is rather intuitive.
- Documentation. Building upon that, data contracts serve as a form of documentation for a dapp. Users should be able to view a contract’s schema and get a basic understanding of what the dapp does and how, especially if the comment and description sections are utilized.
- Indexing. Data contracts allow developers to easily index properties simply by specifying them in the schema, whereas with today’s smart contract languages, the process is much more involved and usually requires multiple data structures. This functionality is made possible thanks to Dash Platform’s GroveDB, the first database to enable verifiable queries on secondary indexes.
- Versioning. Data contracts include versioning information so they may be updated as the needs of the dapp evolve over time – while maintaining backward compatibility.
While smart contracts, which are a top priority following the launch of v1, will synergize with data contracts to enable a much wider range of capabilities for dapps on Dash Platform, there are still many possibilities with data contracts alone. Dash Incubator developer Pshenmic has provided us with a few examples he’s personally excited about:
- Web3 data persistence. If an application does not need heavy read/write operations, it can use Dash Platform’s data contracts as a persistent storage with proofs and indexing. Users can store user accounts, settings, or whatever with the benefits of a decentralized Web3 platform. Dash Platform also gives the option of immutable storage for those who want data permanency.
- Chat rooms. Users can post, edit, or delete messages as documents on a chat room data contract. There’s actually an application that already does this: https://dashshoutout.com.
- Order applications. Users can submit a document to a restaurant’s data contract with their desired meal order. The restaurant’s backend will then be able to pick it up and process their order.
- Signatures repository. Users can upload their public keys to a data contract and a counterparty will be able to pull them without relying on any centralized storage. For example, consider SSH pubkeys. Remote servers will be able to easily give anyone access using the Identity or DPNS username uploaded to their (or some other) data contract.
- Oracles. There is a growing demand in the crypto payment process for shops and other merchants. As a site owner, you often don’t want to deal with payment processing development, and instead you just delegate it to the centralized APIs like Coingate. With Dash Platform, users could upload addresses that they would like to listen to in the data contract (in this case the customers’ addresses), and the oracle backend will pick it up and start listening in on these. As the payment arrives to the ledger, the oracle backend will be able to publish transaction details to Platform. Since all the data is published on-chain, oracle backends are 100% verifiable.
If you’re interested in reading more about possible applications that data contracts enable on Dash Platform, check out this awesome 2021 article from Hackernoon: Building dapps On Dash: An Interview With readme.
Now, onto the architecture.
Architecture
As already stated above, a Dash Platform data contract is a JSON schema that defines the structures of the data a dapp can store. It defines the allowed properties, the validation logic, and the indexes created on the properties.
A Dash Platform data contract JSON schema must define at least one document type. A document type defines a type of document that can be submitted to a data contract. They require three fields: type
, properties
, and additionalProperties
, and support two optional fields: indices
and required
. A data contract with one document type, nft, that employs all five fields, might look like this, for example:
{
"nft": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the NFT token",
"maxLength": 63
},
"description": {
"type": "string",
"description": "Description of the NFT token",
"maxLength": 256
},
"imageUrl": {
"type": "string",
"description": "URL of the image associated with the NFT token",
"maxLength": 2048,
"format": "uri"
},
"imageHash": {
"type": "array",
"description": "SHA256 hash of the bytes of the image specified by tokenImageUrl",
"byteArray": true,
"minItems": 32,
"maxItems": 32
},
"imageFingerprint": {
"type": "array",
"description": "dHash the image specified by tokenImageUrl",
"byteArray": true,
"minItems": 8,
"maxItems": 8
},
"price": {
"type": "number",
"description": "Price of the NFT token in Dash",
"minimum": 0
},
"quantity": {
"type": "integer",
"description": "Number of tokens in circulation",
"minimum": 0
},
"metadata": {
"type": "array",
"description": "Any additional metadata associated with the NFT token",
"byteArray": true,
"minItems": 0,
"maxItems": 2048
}
},
"indices": [
{
"name": "price",
"properties": [
{
"price": "asc"
}
]
},
{
"name": "quantity",
"properties": [
{
"quantity": "asc"
}
]
},
{
"name": "priceAndQuantity",
"properties": [
{
"price": "asc"
},
{
"quantity": "asc"
}
]
}
],
"required": [
"name",
"price",
"quantity"
],
"additionalProperties": false
}
}
Figure 1: A Dash Platform data contract with one document type, “nft”.
Document types in Dash Platform are JSON objects, and therefore must specify "type":"object"
. They must also specify a set of properties
containing at least one property, and "additionalProperties":false
. Optionally, they may also include a list of indices
and a list of required
properties. Here is an example of a valid nft
document (with some truncated fields) that could be submitted to the above data contract:
{
"name": "Dash Cat 001",
"description": "The original Dash Cat. Meow.",
"imageUrl": "https://ipfs.io/ipfs/Qme7ss3ARVgxv6rXqVPiikL…",
"imageHash": [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, …],
"price": 50,
"quantity": 1
}
Figure 2: A valid document (with some truncated fields) that could be submitted to the data contract in Figure 1.
In this document, all the properties listed in the data contract’s required
field are present. There are no additionalProperties
(properties that aren’t defined in the contract’s properties
set), and each property value conforms to that individual property’s validation rules (for example, imageUrl
‘s length is under the set maxLength
of 2048, and is of URI format). References to this document are automatically stored in the corresponding indexes defined in indices
, while the document itself is serialized and stored in the contract’s primary index.
System Properties
In addition to the user-defined properties, like name
and price
, there are some additional “system properties” that data contracts may include in indices
. These are $ownerId, $createdAt, and $updatedAt. $createdAt and $updatedAt may also be included in the list of required
properties, as they are optional when submitting a document at the system level, but $ownerId is always required, so it’s not allowed in the user-defined required
list.
See the DPNS and Dashpay data contracts for two real-world examples that utilize more than one document type.
Before leaving off with Additional Architecture Details, which might be too involved for some readers, I’ll wrap up now by saying you may also be interested in checking out the data contract documentation for further information, and as always, the community, including Dash Core Group and myself, is available to field questions and suggestions on the Dash Discord.
Finally, don’t forget to check out dashpay.io (Github repo here), where you can use AI to automatically generate a data contract based on a description of your intended dapp, use a dynamic form to tweak it to perfection, and save time and money by validating your data contract before submitting it to Dash Platform.
Additional Architecture Details
Indices
The data contract in Figure 1 defines three indices: price
, quantity
, and priceAndQuantity
. When a document is submitted to the data contract, the full serialized document will go into the primary index
, which is a subtree with key 0 in the “nft” tree, and references to the document will automatically be inserted into the three secondary index
subtrees. This is illustrated in the diagram below, where solid lines are actual parent-child relationships within a tree, and the dashed lines point to the node where the root hash of that tree is stored.
Figure 3: The structure of a document type tree in Dash Platform.
Contract Documents Tree
In the GroveDB structure of Dash Platform, all data contracts and their corresponding documents are stored in the Contract Documents tree, which is a subtree of the Root tree. The diagram below shows the path from the Root tree to the “nft” document type tree shown in the diagram above.
Figure 4: The path from the Dash Platform Root Tree to the “nft” document type tree from Figure 3.