You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4545b88
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: book/src/contract-keywords/generated-from.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -42,7 +42,7 @@ A client creates `{ "label": "Bob" }` and the stored document holds `{ "label":
42
42
43
43
The generated property needs no `pattern` of its own. Every value it can hold is what the function generates from params that passed their own patterns: here `label` admits ASCII letters, digits and `-`, so `normalizedLabel` can only ever hold `a` to `z` without `i`, `l` and `o`, digits and `-`. It keeps `maxLength` because it is indexed, and an indexed string declares one of at most 63.
44
44
45
-
This is the rule the DPNS `domain` type's data trigger checks today for `normalizedLabel` and `normalizedParentDomainName`, written into the schema.
45
+
The DPNS `domain` type declares this rule for `normalizedLabel` and `normalizedParentDomainName` from protocol version 15 (DPNS contract v3). Before it, the type's create data trigger checked the same rule.
Copy file name to clipboardExpand all lines: book/src/contract-keywords/ownership-and-trading.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -64,7 +64,7 @@ Whether an owner may give a document to another identity.
64
64
65
65
- The owner sends a transfer transition naming the document, the recipient and a `$revision` one higher than the stored one (`InvalidDocumentRevisionError`, 40106). Only the owner may transfer (`DocumentOwnerIdMismatchError`, 40102). The recipient does not have to agree.
66
66
- The document gets the recipient as its `$ownerId` and a new `$revision`. A price it was listed at is removed, so a transferred document is no longer for sale. When the type lists `$transferredAt` in `required`, it is set to the block's time, and likewise `$transferredAtBlockHeight` and `$transferredAtCoreBlockHeight` to the block heights.
67
-
- A transfer carries no property values, and `$creatorId` keeps naming the identity that created the document. The one change the platform makes itself: from protocol version 13, a DPNS `domain` that is transferred or sold has its `records.identity` pointed at the new owner.
67
+
- A transfer carries no property values, and `$creatorId` keeps naming the identity that created the document. The one change the platform makes itself: from protocol version 13, a DPNS `domain` that is transferred or sold has its `records.identity` pointed at the new owner. From protocol version 15 the type's `recordsIdentityIsOwner` rule holds a new name's `records.identity` to its owner until it first changes hands (see [propertyConstraints](property-constraints.md)), so a name can not be transferred or sold in the block that created it.
68
68
- The document is checked as it will be stored, with its new owner: against the type's unique indexes (`DuplicateUniqueIndexError`, 40105), against a `distinctFrom: "$ownerId"` property (`DocumentPropertyNotDistinctError`, 10419), and against the `propertyConstraints` rules that read what a transfer changes: `$ownerId`, `$transferredAt` and its heights or `$revision`, of the document or, through `$old.`, of the version before the transfer, or a total that depends on the owner (`DocumentPropertyConstraintViolatedError`, 10422; see [propertyConstraints](property-constraints.md#how-it-works)).
69
69
- On a moderated contract, a transfer to a banned or suspended identity is refused (`ContractModerationCounterpartyBarredError`, 41114).
70
70
- A transfer of a document past its `ttl` expiry is refused (`DocumentExpiredError`, 40140).
Copy file name to clipboardExpand all lines: book/src/contract-keywords/property-constraints.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -198,6 +198,7 @@ A rule can read when the document was created, last updated and last transferred
198
198
-`{ "lessThanOrEqual": [{ "subtract": ["endsAt", "$createdAt"] }, 604800000] }` keeps a listing to a week from its creation.
199
199
-`{ "lessThanOrEqual": ["$updatedAt", "endsAt"] }` refuses a replace or a price update after the listing ends.
200
200
-`{ "lessThanOrEqual": ["$transferredAt", "endsAt"] }` refuses a transfer or a purchase after it ends.
201
+
-`{ "ifThen": [{ "equal": ["$transferredAt", "$createdAt"] }, { "equal": ["records.identity", "$ownerId"] }] }` holds `records.identity` to the owner until the document first changes hands. A create records its block's time as the transfer too, so the condition holds on the create, and a transfer or a purchase in a later block records a later time, so it no longer reads the property. One in the block that created the document records that block's time, so the rule still applies to it: a new owner other than `records.identity` is refused. The DPNS `domain` type's `recordsIdentityIsOwner` (protocol version 15) is this rule.
201
202
202
203
A rule may read one only when the document type records it by listing it in `required`, so every stored document holds it. None takes an `ifAbsent` default, `present` and `absent` refuse them, and an [index-only](index-only.md) type reads none. Each write is judged with the values the stored document ends up with: a create with its block's time and heights for all three events; a replace with the stored creation and transfer values and its block's as the update; a price update with its block's as the update; a transfer or a purchase with its block's as the transfer.
203
204
@@ -273,7 +274,7 @@ A write that changes no property is not judged against a rule that compares prop
273
274
|`{ "sumOf": ["pledge", "amount"] }`| The total `amount` over every `pledge`|`documentsSummable: "amount"`|
274
275
|`{ "sumOf": ["pledge", "amount", { "campaignId": "campaignRef" }] }`| The total over those matching the filter | An index with `summable: "amount"` whose properties are exactly the filter's keys |
275
276
276
-
A filter maps each key, a property of the counted type or `$ownerId`, to the value it must take, read from the document being written: one of its properties (`"campaignRef"`), `$ownerId`, `$id` (its own id, for an identifier key), an integer, or a `{ "const": ... }` string or base58 identifier. The counted type may be the rule's own. `$id` counts the documents pointing at this one: `{ "countOf": ["vote", { "pollId": "$id" }] }` is how many votes name the poll being written.
277
+
A filter maps each key, a property of the counted type or `$ownerId`, to the value it must take, read from the document being written: one of its properties (`"campaignRef"`), `$ownerId`, `$id` (its own id, for an identifier key), an integer, or a `{ "const": ... }` string or base58 identifier. From protocol version 15 a key may also be a byte array property, matched by a byte array property of the document: `{ "countOf": ["preorder", { "nameHash": "nameHash" }] }` counts the preorders holding the same hash as the one being written. The counted type may be the rule's own. `$id` counts the documents pointing at this one: `{ "countOf": ["vote", { "pollId": "$id" }] }` is how many votes name the poll being written.
277
278
278
279
```json
279
280
"propertyConstraints": {
@@ -393,7 +394,7 @@ The parser then checks the rules against the document type (`InvalidContractStru
393
394
- no `anyOf` or `allOf` lists two conditions that parse alike, such as `1` and `1.0`, or two `in` conditions listing the same values in another order, and no `ifThen` or `ifThenElse` holds two alike conditions;
394
395
- no condition or operand nests more than 64 levels deep;
395
396
- once every document type of the contract is parsed, every `countOf` and `sumOf` counts a type of the contract that is not index-only, and not its own type when that has a contested index, with a tree that keeps the total as set out in [Totals of other documents](#totals-of-other-documents). A unique, contested, ranked, time-range, integer-range or index-only-terminal index keeps no such total, nor does one with more properties than the filter has keys;
396
-
- every key of a filter is `$ownerId` or an integer, string or identifier property of the counted type, and its value is of the same kind (`$ownerId` and `$id` are identifiers); a string constant is in the key's `enum` when it has one, and an identifier constant is base58;
397
+
- every key of a filter is `$ownerId` or an integer, string or identifier property of the counted type, or from protocol version 15 a byte array property, and its value is of the same kind (`$ownerId` and `$id` are identifiers, and a byte array key takes a byte array property, never a constant); a string constant is in the key's `enum` when it has one, and an identifier constant is base58;
397
398
- every property a filter value reads is listed in `required`, with every object around it, so a write always has the value; an index-only type has no rule reading a total;
398
399
- a `referenced` reads through a property of the type holding one reference to one document, as set out in [Values of a referenced document](#values-of-a-referenced-document), only in `propertyConstraints` (not `deleteConstraints`, an `immutable` condition or `retractedWhen`, whose writes check no reference), not on an index-only type, and not beside what a write checking no reference changes: what a transfer or purchase of the type changes (`$ownerId`, `$transferredAt` and its heights or `$revision`, of either version, or a total depending on the owner), what a price update of the type changes (`$updatedAt` and its heights or `$revision`, of either version), on a type keeping fields for its moderators one of those fields or `$revision`, of either version, or any total, and, on a type whose moderators' deletions keep records, any total;
399
400
- once every document type of the contract is parsed, what a rule reads of a referenced type of the same contract is a field that type gives it: one it has, stored, of the kind the rule reads, a time or height it records, a `$creatorId` it records, a constant its `enum` lists, and through a `moderatedDocument` reference a field its removal record keeps. A referenced type of another contract is checked at registration against the stored contract, refused with `ReferencedDocumentRuleReadInvalidError` (40148).
Copy file name to clipboardExpand all lines: book/src/contract-keywords/refers-to-lookup.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -239,6 +239,8 @@ and the `domain`, which can be transferred, declares on its creator:
239
239
}
240
240
```
241
241
242
+
DPNS v3 declares this reveal on its `domain` from protocol version 15, its preorders living an hour, with the `where` entry `"$ownerId": "$ownerId"` and `consume`, so the reveal deletes the preorder it found.
243
+
242
244
`findBy` finds the writer's own preorder of the name, from an earlier block, by the hash of the name, which every preorder of the name holds, whoever made it. `among` names that property: the preorders holding the same value there are the group the found one is chosen among. `validWhen` says when a preorder of the group counts: it holds, at `ownerNameHash`, the hash of its own owner's id and the name, which only an identity knowing the name can compute (`"$ownerId"` there stands for each preorder's owner). `by` orders the group. When the domain is created, the platform checks the found preorder and then reads:
243
245
244
246
```sql
@@ -261,6 +263,7 @@ LIMIT 1000 -- max_choose_f
261
263
-**Another identity's.**`findBy` finds the found preorder through the unique index over `$ownerId` and `nameHash`, which holds one preorder of a name per identity, and the writer's is the one found, so every competitor read is another identity's.
262
264
-**Consumed.** With `consume` (beside the `where` entry `"$ownerId": "$ownerId"`), a reveal deletes the preorder it found, which then precedes nobody, so a later reveal of the same name by another identity, a contested join, is judged as if it had never existed.
263
265
-**The bound.** The competitors are read in one query, in `by` order and only as far as the found preorder's value of the first ordered property, at most `max_choose_first_candidates` of `SystemLimits` (1,000 at protocol version 14). When none of them refuses, the create stands: refusing past the bound would let anyone block a name with copies. Each identity holds one preorder of a name, so pushing an older valid preorder past the bound takes 1,000 other identities, each paying for a preorder of the name ordered before the hidden one. Ordered by `$createdAtBlockHeight` ascending, as here, those land no later than the hidden one's block, while that one is still pending: a copy made once it is in state comes after it. Another `by` loses that timing: ordered newest first, copies posted after a valid preorder lands come before it and can fill the bound, and a property its creator picks can place a later copy ahead of it. Copies and expired preorders make a create cost more, never refuse it.
266
+
-**Holding a group to the bound.** A contract can keep every group within the bound, so a reveal always reads all of the preorders before its own: a `countOf` rule on the referenced type keyed by `among` (a byte array key, from protocol version 15), counted through a countable index over `among` alone. DPNS v3 declares `atMostAThousandPerName`, `{ "lessThanOrEqual": [{ "countOf": ["preorder", { "nameHash": "nameHash" }] }, 1000] }`, the bound itself. The count holds every stored preorder of the name, expired ones the cleanup has not removed included, so no valid preorder is ever left unread. A preorder past a thousand is refused instead (`DocumentPropertyConstraintViolatedError`, 10422) until one of the name is consumed, deleted or cleaned up: 1,000 copies of a name's hash, from 1,000 identities renewing them as they expire, keep a name from being preordered, where one valid preorder older than another identity's already wins a name easy to guess.
264
267
-**Billing.** The `findBy` hash is billed as the double SHA-256 it is, the found preorder's `validWhen` hash too, the query as the document fetch it is, and `validWhen` computed for each competitor as a double SHA-256. The query and the competitors' hashes together bill at most the scan's budget: `choose_first_credits_per_candidate` of the fee schedule (100,000 credits at protocol version 14) times the candidate limit, 100,000,000 credits (0.001 DASH). Check tx does not validate a reveal's state, so it holds the signer to that whole budget, and to the `findBy` and `validWhen` hashes priced by the reveal's own values (a transient param counts, though nothing stores it), on top of the reveal's estimated fee: a reveal admitted to the mempool can always pay for its `chooseFirst` check in a block, where it is charged only what the check costs. Like any fee check, this holds for the balance the signer had when admitted.
265
268
-**What it does not hide.** The `findBy` hash carries no salt: every preorder of a name holds the same one, so a preorder of a name easy to guess discloses it, from the moment it is broadcast. Guessed from a preorder already in a block, the name comes too late: a commitment to it lands in a later block, after the original, which precedes it. Guessed from a preorder still pending, it does not: the guesser can commit to the name and outbid the original, landing in the same block (where neither counts and the name's unique index decides between the reveals) or in an earlier one, whose commitment then comes first. `chooseFirst` settles the race to reveal; for a name easy to guess, the race to commit stays open.
Copy file name to clipboardExpand all lines: book/src/contract-keywords/transient.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@
13
13
14
14
## Example
15
15
16
-
The DPNS `domain` type, trimmed to two properties:
16
+
The DPNS `domain` type of contracts v1 and v2, trimmed to two properties:
17
17
18
18
```json
19
19
"domain": {
@@ -36,11 +36,11 @@ The DPNS `domain` type, trimmed to two properties:
36
36
}
37
37
```
38
38
39
-
Registering a name takes two steps. A `preorder` document first commits to a hash of the salt and the name, and the `domain` document then reveals both. Every domain create must carry its 32-byte `preorderSalt`, and DPNS checks it against the preorder. Once the domain is created the salt has done its job, and the stored domain does not hold it.
39
+
Registering a name took two steps. A `preorder` document first committed to a hash of the salt and the name, and the `domain` document then revealed both. Every domain create carried its 32-byte `preorderSalt`, which the type's create data trigger checked against the preorder. Once the domain was created the salt had done its job, and the stored domain does not hold it. DPNS v3 (protocol version 15) finds the preorder by its creator and the hash of the name instead, choosing the first valid preorder of the name ([Choosing the first commitment](refers-to-lookup.md#choosing-the-first-commitment-choosefirst)), and keeps `preorderSalt` declared, transient and unused, so domains stored under v1 and v2 decode.
40
40
41
41
## How it works
42
42
43
-
-**Checked like any other value.** A transient value is on the transition when the document is validated, so the schema holds it to its rules: a required transient property must be present, and its bounds apply. `maxBytes` and `distinctFrom` apply to it too, and so do checks such as the DPNS one above.
43
+
-**Checked like any other value.** A transient value is on the transition when the document is validated, so the schema holds it to its rules: a required transient property must be present, and its bounds apply. `maxBytes` and `distinctFrom` apply to it too, and so do checks such as the DPNS v1 and v2 one above.
44
44
-**Dropped before storing.** After validation, a create drops the transient values before the document is written. From protocol version 14 a replace drops them the same way. Before 14 a replace stored the values it carried, so a replaced document could hold values its create had dropped.
45
45
-**Dropped by top-level name.** Only top-level properties can be transient. When a transient property is an object, the whole object is dropped with everything in it.
46
46
-**Never stored, never found.** No stored document holds a transient value, so a query cannot find one and a later reader cannot see it.
0 commit comments