|
| 1 | +# What a Document Costs |
| 2 | + |
| 3 | +`drive::document::cost` computes what creating one document costs, from the |
| 4 | +contract alone. The JavaScript SDKs expose it as |
| 5 | +`documentCreateCost(contract, documentTypeName, options, platformVersion)`, |
| 6 | +which is what the contract visualizer shows per document type. |
| 7 | + |
| 8 | +Amounts are in credits: 1 Dash is 100,000,000,000 credits. |
| 9 | + |
| 10 | +## Storage |
| 11 | + |
| 12 | +The storage fee is the bytes the insert adds times |
| 13 | +`storage_disk_usage_credit_per_byte` (27,000 credits from protocol version 14). |
| 14 | +It is usually almost all of what a document costs. |
| 15 | + |
| 16 | +The estimate is exact. It lists every element the insert writes (see |
| 17 | +[GroveDB Structure](../drive/grovedb-structure.md) for the layout), built with |
| 18 | +the functions the insert walkers use: |
| 19 | + |
| 20 | +- the document by id, or with `documentsKeepHistory` a tree of revisions and a |
| 21 | + pointer to the newest; |
| 22 | +- for each index, the value trees along its properties (created only when no |
| 23 | + earlier document has the value), the `[0]` terminal and the document's |
| 24 | + reference in it, or an indexOnly type's entry; |
| 25 | +- the rows a ranked index keeps for the value in its secondary trees, one per |
| 26 | + ranking axis; |
| 27 | +- the trees preallocated for other document types' `preallocated` indexes |
| 28 | + whose entries will reference the document, charged to its creator. |
| 29 | + |
| 30 | +Each element is priced with GroveDB's byte formulas: the key with the 32-byte |
| 31 | +subtree prefix, the serialized element (or a fixed size standing for a tree), |
| 32 | +the value and node hashes, the aggregate feature of the tree it sits in (8 or |
| 33 | +16 bytes in a count or sum tree), and the link its parent keeps to it. A |
| 34 | +document create's elements carry 35 bytes of storage flags (the owner and the |
| 35 | +epoch); index trees carry them only when the documents are mutable, the |
| 36 | +contract can be deleted, or the type is indexOnly and its documents can be |
| 37 | +deleted. |
| 38 | + |
| 39 | +The storage depends on what is already stored, so it comes in two scenarios: |
| 40 | + |
| 41 | +- **every value new**: the first document with these index values creates |
| 42 | + their trees; |
| 43 | +- **every value known**: a later document with the same values adds only its |
| 44 | + own entries. A unique index still adds its value, which no earlier document |
| 45 | + can hold, as does every tree keyed by the document's own id (a preallocated |
| 46 | + index's, say) and a `ttl` document's expiration entry; a ranked index's row |
| 47 | + for an existing value only moves, which GroveDB bills as replaced bytes. |
| 48 | + |
| 49 | +The estimate also splits the storage by index: the layers an index shares with |
| 50 | +other indexes (a common prefix of properties, paid once for the document) and |
| 51 | +the layers only it uses, so an index's cost on its own is its shared layers |
| 52 | +plus its own. |
| 53 | + |
| 54 | +The test `should_price_what_drive_charges` inserts documents into 19 contracts |
| 55 | +covering every index shape and requires the estimate to equal the storage fee |
| 56 | +Drive charged, byte for byte, with the trees already stored read from GroveDB |
| 57 | +before each insert. |
| 58 | + |
| 59 | +## Processing |
| 60 | + |
| 61 | +- **Exact:** verifying the signature (15,000 credits for an ECDSA key, 300,000 |
| 62 | + for BLS) and fetching the signing key and the identity's balance (18,000). |
| 63 | +- **Estimated:** the work of the writes (seeks, hashing and rewriting the path |
| 64 | + to each new element in its tree and above), for an assumed number of stored |
| 65 | + documents, each with its own values (1,000 by default); and the small reads |
| 66 | + and writes around the insert (the document id check and the identity's |
| 67 | + contract nonce). The test |
| 68 | + `should_estimate_the_processing_of_the_writes_within_a_factor_of_two` holds |
| 69 | + the write estimate to Drive's processing fee. Processing is a few percent of |
| 70 | + a document's cost. |
| 71 | +- A `userFeeIncrease` raises the processing fee only. |
| 72 | + |
| 73 | +The per-document "minimum fee" of a batch (`document_batch_sub_transition`) is |
| 74 | +a balance check before processing, not a charge, and the unique index checks |
| 75 | +and the fetch of the batch's own contract are not billed. |
| 76 | + |
| 77 | +## What the contract adds |
| 78 | + |
| 79 | +- **Action fees** (`actionFees`): the create's fee, in credits, scaled by the |
| 80 | + epoch's fee multiplier unless priced as fixed, paid into the contract's fee |
| 81 | + pots. |
| 82 | +- **Token cost** (`tokenCost`): tokens transferred to the contract owner or |
| 83 | + burned. |
| 84 | +- **Contest fund**: a contested index's vote fund (0.1 Dash, doubling past 250 |
| 85 | + contenders), paid when the value is contested. |
| 86 | + |
| 87 | +## Refunds |
| 88 | + |
| 89 | +Deleting a document refunds the storage fee of its flagged elements, less what |
| 90 | +the epochs already passed were paid: about 99.9% in the epoch it was created, |
| 91 | +about 95% a year later, then less each year for fifty years. |
| 92 | + |
| 93 | +## Documents with a `ttl` |
| 94 | + |
| 95 | +A document whose type declares a [`ttl`](../contract-keywords/ttl.md) is |
| 96 | +stored without flags and pays for its bytes by the lifetime it has left, all of |
| 97 | +its `ttl` when it is created, at the schedule's tier for that lifetime (from 1 |
| 98 | +credit per byte for an hour to 26 for a week, then 34 per 788,400 seconds) |
| 99 | +instead of the 27,000 of storage kept for good. It also adds its entry to the |
| 100 | +documents expirations tree, and prepays its deletion as processing (a base |
| 101 | +cost, a cost per index level and one per document byte). Nothing of it is |
| 102 | +refunded. |
| 103 | + |
| 104 | +## Not covered |
| 105 | + |
| 106 | +- A create whose value starts a contest (a DPNS name matching the contest |
| 107 | + rule, say) is stored in the contest's vote poll until the contest ends, not |
| 108 | + in the index. The estimate prices an uncontested create and lists the contest |
| 109 | + fund; the vote poll's storage is not priced. |
| 110 | +- A platform version whose insert methods differ from protocol version 14's is |
| 111 | + refused: other versions write other elements for some shapes. |
0 commit comments