Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
5b923eb
feat(platform)!: keyRequirements on identity key references (PV14)
QuantumExplorer Sep 22, 2026
16b61e8
Merge branch 'v4.2-dev' of github.com:dashpay/platform into claude/vi…
QuantumExplorer Sep 22, 2026
a212b46
test(drive-abci): use fn pointers for the wrong-purpose key cases
QuantumExplorer Sep 22, 2026
5d1b985
test(drive-abci): fixture types declare that they take bound encrypti…
QuantumExplorer Sep 22, 2026
87d0b00
docs(book): a boundTo type must declare the bound key keyword of the …
QuantumExplorer Sep 22, 2026
07fd48c
fix(platform): refuse key requirements no key could ever meet, review…
QuantumExplorer Sep 22, 2026
83782df
Merge branch 'v4.2-dev' of github.com:dashpay/platform into claude/vi…
QuantumExplorer Sep 22, 2026
4d4fee4
docs(wasm-dpp2): the reference error code getter lists every code it …
QuantumExplorer Sep 22, 2026
882d619
Merge branch 'v4.2-dev' of github.com:dashpay/platform into claude/vi…
QuantumExplorer Sep 22, 2026
10c0527
Merge branch 'v4.2-dev' of github.com:dashpay/platform into claude/vi…
QuantumExplorer Sep 22, 2026
db1f315
Merge branch 'v4.2-dev' of github.com:dashpay/platform into claude/vi…
QuantumExplorer Sep 22, 2026
c8126c3
Merge branch 'v4.2-dev' into claude/vigorous-lovelace-4321ef
QuantumExplorer Sep 22, 2026
c725e7b
fix(dpp): the key requirement purpose deserializer refuses system lik…
QuantumExplorer Sep 22, 2026
2fbc764
refactor(dpp): fold the boundTo post-pass into generation 1 of the do…
QuantumExplorer Sep 22, 2026
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
2 changes: 2 additions & 0 deletions book/src/data-model/contract-moderation.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ The declaration lives in `packages/rs-dpp/src/data_contract/config/moderation/el

**Referencing an elected contract.** A document type that must point at a contract of this kind says so in its reference: `"refersTo": { "type": "contract", "contractRequirements": { "moderation": "elected" } }`. `contractRequirements` holds what the referenced contract must declare beyond existing, each key an aspect of the contract with a closed set of values or a bound: `moderation: "elected"`, or `moderation: "electionOpen"`, which also requires the contract's own election delay to have passed since its creation, or the contract to declare none (the delay between a contract's creation and the first charter against it, so a team cannot be seated before anyone has seen the contract, set by each contract for itself). Both have a user in the charter contract: a charter proposal only needs the target to be `elected`, so teams can form during the notice, and the charter that opens the contest needs its election `electionOpen`; `minimumAgeSeconds`, a number of seconds the reference fixes, which requires the contract's recorded creation time to be at least that far before the block time of the write; `minimumSecondsSinceUpdate`, the same of the later of the contract's creation and last update times (any update restarts the clock; an elected declaration can not be added by an update, so this one is for other uses than the charter); `owner`, `"self"` requiring the referenced contract to be owned by the writer of the referring document (its `$ownerId`, a write gate like the `$ownerId` property agreement of a document reference) and `"other"` by anyone else (so a charter may forbid an owner from chartering its own team); `readonly: true`, requiring the referenced contract's config to be read-only, one that can never be updated again (which makes `minimumSecondsSinceUpdate` moot for the same target); `keepsHistory: true`, requiring its config to keep history (only `true` is declarable for either flag); and `ownerProtected`, requiring the contract's elected moderation declaration to protect the owner from the team (`true`) or to leave it unprotected (`false`), which implies elected moderation without the schema having to say so, a contract without an elected declaration meeting neither value. A contract created before contracts recorded their creation time never meets a duration, its own election delay included. Consensus checks them when the referring document is written, against the contract it has already fetched for the existence check and the write itself (its owner and block time), so they cost no further read; a contract that exists but does not meet a requirement refuses the write, paid, with `ReferencedContractRequirementNotMetError` (40135) naming the requirement, where a contract that does not exist is still 40120. A changed `contractRequirements` is an incompatible schema change on update, like the rest of a `refersTo`. The charter system contract's `targetContractId` is the first user.

**Referencing an identity key with requirements.** The same shape serves the key references the charter contract needs: `"refersTo": { "type": "identityPublicKey", "keyIdProperty": "recipientKeyId", "keyRequirements": { "purpose": "decryption", "boundTo": "submittedCharter" } }`. `keyRequirements` holds what the referenced key must be beyond existing and not being disabled, each key an aspect of the key: `purpose`, the key's purpose by its wire name (`authentication`, `encryption`, `decryption`, `transfer`, `voting` or `owner`; never `system`), and `boundTo`, the name of a document type of the declaring contract, which requires the key's contract bounds to be exactly the declaring contract and that document type; a whole-contract bound or a contract group bound never meets it, even where the group holds the type, since the check reads nothing beyond the key. Registration (`create_document_types_from_document_schemas` 1, a post-pass edited in place since it is inert before protocol version 14, under full validation like the meta-schema) checks that `boundTo` names a document type the contract has, so the write-time check never needs a second contract fetch, and that a key meeting the pair can exist at all: only authentication, encryption and decryption keys carry a document type bound, and Drive registers an encryption or decryption key bound to a document type only when that type declares `requiresIdentityEncryptionBoundedKey` or `requiresIdentityDecryptionBoundedKey`, so a `boundTo` paired with `transfer`, `voting` or `owner`, or with an encryption purpose on a type without the matching keyword, is refused as a requirement no key could ever meet. Consensus checks the requirements when the referring document is written, against the key it has already fetched for the existence check, so they cost no further read; a key that exists and is enabled but does not meet one refuses the write, paid, with `ReferencedIdentityKeyRequirementNotMetError` (40136) naming the document type, the property, the requirement and what the key has, where a missing key is still 40123 and a disabled one 40124. A replace that repoints the reference at another key, through either the identity id or the key id, re-checks them. A changed `keyRequirements` is an incompatible schema change on update, like the rest of a `refersTo`. New requirements (a security level, say) are new keys of the same object, never a new reference type. The charter contract's `joinRequest.recipientId` (a decryption key bound to `submittedCharter`) is the first user.

**What comes next.** The charter system contract, applications and the election (new vote poll kinds), the seated team under the contract with its per-ability powers, charter-priced moderators amounts within the maximums, and challenges and amendments. Issue #4865 holds the design.

## Versioning Touchpoints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,30 @@
"maxLength": 256,
"pattern": "^[a-zA-Z0-9_]{1,64}(\\.[a-zA-Z0-9_]{1,64})*$"
},
"keyRequirements": {
"description": "identityPublicKey references only: what the referenced key must be beyond existing and not being disabled, checked when the referring document is written against the key already fetched for the existence check, so a requirement costs no further read. Each key names an aspect of the referenced key and its value the requirement: purpose requires the key's purpose to be the named one (any but system); boundTo names a document type of the declaring contract and requires the key's contract bounds to be exactly the declaring contract and that document type (a whole-contract or contract group bound never meets it). At registration boundTo must name a document type the contract has, and one a key of the required purpose can be bound to: only authentication, encryption and decryption keys carry a document type bound, and an encryption or decryption key only where the type declares requiresIdentityEncryptionBoundedKey or requiresIdentityDecryptionBoundedKey. An unmet requirement refuses the write (ReferencedIdentityKeyRequirementNotMetError, 40136)",
"type": "object",
"properties": {
"purpose": {
"enum": [
"authentication",
"encryption",
"decryption",
"transfer",
"voting",
"owner"
]
},
"boundTo": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-zA-Z0-9_]{1,64}$"
}
},
"minProperties": 1,
"additionalProperties": false
},
"propertyAgreement": {
"description": "permanentDocument and deletableDocument references only: each { referring property: referenced property } pair must hold as an equality between the referring document's value and the referenced document's value, enforced by consensus at document write time. The referring side is a schema property of the declaring document type or its own $ownerId, the writer, which turns the pair into a write gate: only an identity whose id equals the referenced side may create or replace the document. The referenced side is a schema property of the referenced document type, or one of its $ownerId and $creatorId system identifiers, in which case the referring property must be an identifier; $creatorId additionally needs a referenced document type that records creator ids (transferable or tradeable types of a format-1 contract). Both sides must exist and share one value kind, validated at contract registration. $ownerId follows the referenced document through transfers while $creatorId never changes; either is checked when the referring document is written, not when the referenced document later moves",
"type": "object",
Expand Down Expand Up @@ -280,7 +304,8 @@
},
"else": {
"properties": {
"keyIdProperty": false
"keyIdProperty": false,
"keyRequirements": false
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ impl DocumentType {
validation_operations,
platform_version,
),
// in v1 we add the ability to have contracts without documents and just tokens
// in v1 we add the ability to have contracts without documents and just tokens;
// from protocol version 14 it also checks an identity key reference's
// keyRequirements.boundTo, inert before (see v1)
1 => DocumentType::create_document_types_from_document_schemas_v1(
data_contract_id,
data_contract_system_version,
Expand Down
Loading
Loading