platform_version/version/v14.rs
1use crate::version::consensus_versions::ConsensusVersions;
2use crate::version::dpp_versions::dpp_asset_lock_versions::v1::DPP_ASSET_LOCK_VERSIONS_V1;
3use crate::version::dpp_versions::dpp_contract_versions::v6::CONTRACT_VERSIONS_V6;
4use crate::version::dpp_versions::dpp_costs_versions::v1::DPP_COSTS_VERSIONS_V1;
5use crate::version::dpp_versions::dpp_document_versions::v4::DOCUMENT_VERSIONS_V4;
6use crate::version::dpp_versions::dpp_factory_versions::v1::DPP_FACTORY_VERSIONS_V1;
7use crate::version::dpp_versions::dpp_identity_versions::v1::IDENTITY_VERSIONS_V1;
8use crate::version::dpp_versions::dpp_method_versions::v3::DPP_METHOD_VERSIONS_V3;
9use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2::STATE_TRANSITION_CONVERSION_VERSIONS_V2;
10use crate::version::dpp_versions::dpp_state_transition_method_versions::v2::STATE_TRANSITION_METHOD_VERSIONS_V2;
11use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v3::STATE_TRANSITION_SERIALIZATION_VERSIONS_V3;
12use crate::version::dpp_versions::dpp_state_transition_versions::v4::STATE_TRANSITION_VERSIONS_V4;
13use crate::version::dpp_versions::dpp_token_versions::v3::TOKEN_VERSIONS_V3;
14use crate::version::dpp_versions::dpp_validation_versions::v5::DPP_VALIDATION_VERSIONS_V5;
15use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2;
16use crate::version::dpp_versions::DPPVersion;
17use crate::version::drive_abci_versions::drive_abci_checkpoint_parameters::v1::DRIVE_ABCI_CHECKPOINT_PARAMETERS_V1;
18use crate::version::drive_abci_versions::drive_abci_method_versions::v10::DRIVE_ABCI_METHOD_VERSIONS_V10;
19use crate::version::drive_abci_versions::drive_abci_query_versions::v2::DRIVE_ABCI_QUERY_VERSIONS_V2;
20use crate::version::drive_abci_versions::drive_abci_structure_versions::v2::DRIVE_ABCI_STRUCTURE_VERSIONS_V2;
21use crate::version::drive_abci_versions::drive_abci_validation_versions::v10::DRIVE_ABCI_VALIDATION_VERSIONS_V10;
22use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v3::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V3;
23use crate::version::drive_abci_versions::DriveAbciVersion;
24use crate::version::drive_versions::v9::DRIVE_VERSION_V9;
25use crate::version::fee::v3::FEE_VERSION3;
26use crate::version::protocol_version::PlatformVersion;
27use crate::version::system_data_contract_versions::v3::SYSTEM_DATA_CONTRACT_VERSIONS_V3;
28use crate::version::system_limits::v4::SYSTEM_LIMITS_V4;
29use crate::version::ProtocolVersion;
30
31pub const PROTOCOL_VERSION_14: ProtocolVersion = 14;
32
33/// v14 hosts thirty-one consensus changes:
34///
35/// 1. **Contract-level ranked aggregates**: an index can
36/// declare that its groups are rankable by an aggregate, so a query like
37/// "top 5 restaurants by average grade" is served from an ordered
38/// secondary tree in O(log n + k) with a proof, instead of being rejected.
39/// 2. **The shared-prefix aggregate index fix**: a data contract declaring
40/// an aggregating (countable / summable) index that terminates at a
41/// property which is also the prefix of a compound index (e.g. summable
42/// `[a]` next to `[a, b]`) registered successfully but rejected every
43/// document insert for most flag combinations, because Drive could not
44/// legally hang the compound continuation tree under the aggregating
45/// per-value tree. The v2 document index walkers (plus the v1 update
46/// walker) that fix it gate here as well: tree types derive through a
47/// shared continuation-demotion helper (provable count-bearing value
48/// trees with compound continuations demote to `CountSumTree`, since
49/// grovedb rejects count-suppressed children under provable count
50/// parents by design) and continuation inserts route through the
51/// completed zero-contribution wrapper matrix. No state migration is
52/// needed: shapes without compound continuations produce bit-identical
53/// operations, the broken shapes could never hold documents, and the
54/// one previously-insertable shape the demotion changes (a provable
55/// count-bearing value tree whose continuations were all sum-bearing —
56/// insertable pre-v14 only through an unenforced grovedb batch guard)
57/// simply gets `CountSumTree` value trees for values first seen at
58/// v14+, which readers treat identically.
59/// 3. **The contested vote poll index cross-check**: the index named by a
60/// document create transition's prefunded voting balance keys the vote
61/// poll, its stored info, its end-date entry and its prefunded
62/// specialized balance, while the contested index the contender is
63/// inserted under always comes from the document type. Up to v13 nothing
64/// tied the two together, so a submitter could register and fund a
65/// contest under a vote poll describing a different index than the one
66/// the contest was created on — which halts the chain when that poll
67/// ends — or open a contest for a document that is not a contested
68/// resource at all. State validation also prevents a non-contested create
69/// from occupying a live contested document's id before the contest winner
70/// is awarded into primary storage. Drive's contested insert also recreates
71/// an abstain or lock vote tree over the storage an earlier poll's cleanup
72/// left orphaned (it only removed the trees that received votes), so a
73/// resource can be contested again instead of failing with
74/// `CorruptedContractIndexes`.
75/// 4. **Relative daily withdrawal limit**: the flat 2000 Dash per 24 hours that
76/// applied from v8 becomes 15% of the total credits Platform held a day ago
77/// (`SYSTEM_LIMITS_V4.daily_withdrawal_limit_percent`, read by
78/// `daily_withdrawal_limit` v2 through `DPP_METHOD_VERSIONS_V3`), never below
79/// one maximal withdrawal (`max_withdrawal_amount`) so every accepted
80/// withdrawal eventually fits and cannot block the pooling queue. The base has
81/// no fixed cap: what Core will mine bounds pooling through the Core-anchored
82/// limit of note 74 instead. The credit inflows of the active window — every
83/// credit mint, recorded per block by `record_credit_inflows_for_withdrawals`
84/// in the credit inflows sum tree — are added to the base, so the limit
85/// counts net outflow and a matching deposit -> withdraw cycle does not
86/// consume the budget of other users (#4471), mirroring Core v24's net
87/// credit-pool rule. Both the inflows and the pooled reservations count over the
88/// interval after the base snapshot only — an entry the snapshot already
89/// reflects is neither added nor subtracted again. The base is
90/// the total credits recorded at the latest block at least 24 hours before
91/// the current one: `DRIVE_ABCI_METHOD_VERSIONS_V10` turns on
92/// `record_total_credits_history_for_withdrawals`, which checks the total
93/// credits every block once fees and epoch rewards are in, writes it under
94/// the withdrawals tree keyed by block time whenever it changed (an entry
95/// describes the total until the next one) and prunes entries older than the
96/// one the limit reads, and `DRIVE_VERSION_V9`'s identity withdrawal table
97/// bumps `calculate_current_withdrawal_limit` to 1 to read that lagged
98/// value. Until an entry is a day old — the first day after activation — the
99/// flat 2000 Dash keeps applying, so the lag cannot be skipped by inflating
100/// the total before or at activation. The lag is the guardrail: a sudden
101/// jump in the total credits does not raise the limit for a day. Amounts
102/// already pooled in the last 24 hours keep counting against the maximum
103/// exactly as before. Pre-V24 Core caps unlocks at `LimitAmountV22` (2000
104/// Dash) per *block*, with the amount checked only at block level, so any
105/// daily total is still minable across blocks; V24 limits the net drop of
106/// its credit pool per 576-block window, which note 74 follows.
107/// 5. **Time-range indexes**: an index can declare a `timeRange` transform
108/// that buckets a required system timestamp (`$createdAt` /
109/// `$updatedAt` / `$transferredAt`) into fixed-length, regularly-spaced,
110/// optionally overlapping windows declared in seconds (`range` / `step`,
111/// plus an optional `phase < step` alignment offset). Each grid gets its
112/// own index subtree — the level is keyed by the property name qualified
113/// with the grid — so several grids may bucket one timestamp side by
114/// side. A document is stored once per containing bucket per grid (the
115/// v2 insert/delete and v1 update walkers carry the fan-out; the
116/// per-document write amplification is capped per index by
117/// `SystemLimits::max_time_range_overlap_factor`), and the v1
118/// `getDocuments` handler resolves the new `IN_TIME_RANGE` operator —
119/// a typed `TimeRangeSelection` operand: `NEWEST`/`OLDEST` (resolved to
120/// a bucket-start equality from committed block time) or `BY_START`
121/// (naming any window, current or historic, by its grid-aligned start),
122/// with a `grid` member naming one grid where several bucket the field
123/// — making trending/leaderboard document and count/sum/avg queries
124/// provable over the current or any named window. `unique: true` is
125/// admitted only for non-overlapping windows (`range == step`) sourced
126/// from the immutable `$createdAt`.
127/// 6. **Deterministic token reward math**: `DistributionFunction::evaluate`
128/// (logarithmic, inverted-logarithmic, exponential and polynomial perpetual
129/// distributions) computes `ln`/`exp`/`pow` through the pinned pure-Rust
130/// `libm` crate instead of the platform C library. musl's `log` takes an
131/// FMA path on aarch64 and a non-FMA path on x86_64, so the two disagree by
132/// 1 ulp on some inputs; a contract owner could pick parameters whose reward
133/// sat within that ulp of an integer, and `floor` then minted different
134/// amounts on the two architectures, splitting the app hash both at claim
135/// time and at contract registration (validation evaluates the start
136/// value). Gated on `distribution_function_evaluate_version` so both
137/// architectures switch at the same height; pre-v14 blocks replay on the
138/// old math byte-for-byte. `log`/`exp` have no architecture dispatch and
139/// `pow`'s only arch-touching call is the correctly-rounded `sqrt`, so the
140/// result is bit-identical on every target Platform builds for. The goal
141/// is determinism, not correct rounding: on a boundary tuple the host
142/// libm (glibc, macOS) can still be 1 ulp away, so anything predicting
143/// rewards with host math may differ from consensus by one unit.
144///
145/// The first two are orthogonal by construction: the ranked upgrade decides the
146/// *property-name* tree type, the demotion decides the *value* tree type
147/// one level below it, and a demoted `CountSumTree` value tree contributes
148/// its (count, sum) to a ranked indexed parent exactly as the provable
149/// variant did — so ranked secondaries keep ranking correctly over
150/// shared-prefix shapes.
151///
152/// Until a contract uses the ranked or time-range grammar, the only v14
153/// behavior changes are the shared-prefix fix, the contested-index
154/// cross-check, the index-reorder schema-compatibility fix and the relative
155/// daily withdrawal limit; everything else matches v13:
156///
157/// * `CONTRACT_VERSIONS_V6` points `document_type_schema` at the v3 document
158/// meta-schema, which hosts the ranked index keywords
159/// (`rankedCountable` / `rankedSummable` / `rankedAverageable`), the
160/// `refersTo` reference keyword and the `timeRange` index transform. v13
161/// keeps validating against meta-schema v2, where those keys are rejected
162/// as unknown properties, so a pre-v14 contract cannot smuggle them in.
163/// It also bumps `validate_schema_compatibility` to 1, which strips the
164/// top-level `indices` key before diffing the old and new document type
165/// schemas: index immutability is enforced by `validate_update` v1's
166/// name-keyed comparison, so a contract update that merely reorders the
167/// `indices` array validates cleanly instead of hitting the
168/// unsupported-keyword hard error (an internal error under v13).
169/// * `DRIVE_VERSION_V9` carries `DRIVE_DOCUMENT_METHOD_VERSIONS_V4`, adding
170/// the `detect_ranked_mode` routing slot, plus the grove-method slots for
171/// creating the three indexed tree variants and the verify-method slot for
172/// `verify_ranked_top_k_proof`. All are 0 today. The same table bumps the
173/// four index walkers to v2 and the document update walker to v1 for the
174/// shared-prefix fix; those same walker versions carry the time-range
175/// bucket fan-out, so both features gate on one table entry. It also sets
176/// `insert_contested.fetch_charter_election_windows` to `Some(0)`: a
177/// moderation election (an `electedCharter` contest) runs on its target
178/// contract's join and vote windows, which the document create join check
179/// and the contested insert read.
180/// * `DRIVE_ABCI_QUERY_VERSIONS_V2` bumps
181/// `document_query_helpers.compute_aggregate_mode_and_check_limit` 0 → 2,
182/// opening two routes on the v1 document-query handler: the ranked path
183/// (a grouped aggregate whose single `order_by` names the selected
184/// aggregate — `ORDER BY <agg> [ASC|DESC] LIMIT n [OFFSET m]`) and the
185/// boolean-`HAVING` range path (a grouped aggregate carrying exactly one
186/// `having` clause on the selected aggregate — `GROUP BY p HAVING <agg>
187/// <op> <value> LIMIT n`), the latter served as a value-bounded range
188/// read of the covering ranked index's axis secondary. v13 and earlier
189/// keep the v1 table and therefore keep rejecting both shapes, so
190/// mixed-version networks agree across the upgrade.
191/// * `DRIVE_ABCI_VALIDATION_VERSIONS_V10` bumps
192/// `document_create_transition_structure_validation` 0 → 1, requiring a
193/// contested create transition's prefunded voting balance to name the
194/// same vote poll the document itself resolves to, and rejecting one on a
195/// document that resolves to no contested index. It also bumps document
196/// create state validation to 2, enforcing `refersTo` document references
197/// and rejecting a non-contested create whose id is already present in the
198/// contested tree. Document replace state validation 1 enforces the same
199/// reference checks, re-validates a `refersTo: deletableDocument`
200/// reference on every replace (a dead one must be repointed or cleared),
201/// and lets an `immutable` one be cleared once its target is deleted.
202/// Document create structure validation 1 and replace structure
203/// validation 0 (extended in place) refuse a `distinctFrom` identifier
204/// property equal to the value it must differ from
205/// (`DocumentPropertyNotDistinctError`, 10419); transfer and purchase
206/// structure validation 0, extended in place, judge the stored document's
207/// `$ownerId` declarations against the new owner.
208/// v13 keeps the v9 table and therefore keeps accepting all of these, so
209/// replay of pre-upgrade blocks is unchanged.
210/// * `DRIVE_ABCI_VALIDATION_VERSIONS_V10` also bumps the identity create from
211/// addresses `advanced_structure` 0 → 1: a key whose proof of possession fails
212/// is refused unpaid instead of charging the inputs a penalty, since the
213/// address witnesses do not sign those proofs. v13 keeps the paid refusal of v0.
214/// * `DOCUMENT_VERSIONS_V4` bumps `document_serialization_version` to
215/// default 3: documents are stamped with the contract version their bytes
216/// conform to (a varint after the format prefix), enabling the
217/// `requiredSince` property keyword — a contract update may add a new
218/// required property annotated with the version that update creates.
219/// Documents stamped below a property's `requiredSince` keep the
220/// presence-flagged layout they were written with, so the latest contract
221/// alone reconstructs every stamp's layout and no historical contract
222/// lookups are ever needed. Reads dispatch on the byte prefix, so
223/// formats 0–2 (all pre-v14 documents) deserialize exactly as before with
224/// an unstamped (pre-annotation) layout.
225/// 7. **Client-side GroveDB proof envelope floor (not a version-table
226/// entry)**: clients refuse the legacy V0 proof envelope at every protocol
227/// version through
228/// `drive::verify::grovedb_proof_envelope::MINIMUM_GROVEDB_PROOF_ENVELOPE_VERSION`,
229/// so nothing about it is gated on v14. The note keeps its number so the
230/// later notes keep theirs.
231/// 8. **Epoch-based perpetual distribution claims stop wrapping**:
232/// `RewardDistributionType::max_cycle_moment` (the cap on how far one claim
233/// may redeem, selected by
234/// `TOKEN_VERSIONS_V3.reward_distribution_max_cycle_moment_version` 1)
235/// computes `start + interval * cycles` in `u64` with saturating
236/// arithmetic and narrows back to `EpochIndex` only after capping at the
237/// last completed cycle moment (`current cycle moment - interval`, the
238/// previous epoch for an interval of one as before; for wider intervals the
239/// same cycles are paid, but the cap now sits on a cycle boundary, the only
240/// shape in which `evaluate_interval`'s fixed-amount step count and its
241/// per-cycle loop agree). Up to v13 the sum was taken in `u16`: a
242/// fixed-amount function allows 32,767 cycles, so any epoch interval of
243/// three or more with a nonzero start (or two with a start at epoch two
244/// or later) pushed the cap past `u16::MAX`. Release builds wrap, the cap landed below the
245/// start, `evaluate_interval` saw an empty range and the claim was
246/// refused with `InvalidTokenClaimNoCurrentRewards` on every attempt. The
247/// v0 arithmetic is kept, wrapping explicitly, so those refusals replay.
248/// 9. **Evonode reward cycles weighted by the epochs they span**: the
249/// per-cycle evaluator in `DistributionFunction::evaluate_interval` asks
250/// the participation ratio for the epochs a cycle covers
251/// (`TOKEN_VERSIONS_V3.distribution_function_cycle_epochs_version` 1:
252/// `cycle moment - interval + 1 ..= cycle moment`). Up to v13 it passed the
253/// cycle's step index as if it were an epoch, which coincides only for an
254/// interval of one; for a wider interval it named epochs before the
255/// distribution started, outside the epoch window the claim loads, and an
256/// `EvonodesByParticipation` claim with a function other than a fixed
257/// amount failed as an internal error (reachable only once item 8 let the
258/// cap stop wrapping). Interval-one distributions are unchanged.
259/// 10. **A zero epoch interval is rejected at registration**:
260/// `RewardDistributionType::validate_structure_interval` v1
261/// (`CONTRACT_VERSIONS_V6.token_versions.validate_structure_interval`)
262/// refuses an `EpochBasedDistribution` with `interval: 0` with the new
263/// `InvalidTokenDistributionEpochIntervalTooShortError` (code 10828) on
264/// contract create and update. Up to v13 the epoch arm enforced nothing,
265/// so such a contract registered and every claim on it failed as an
266/// internal error, since no cycle can be computed from a zero step. Block
267/// and time minimums are unchanged.
268/// 11. **Gas paid by the contract owner**: a token-paid document action's
269/// `gasFeesPaidBy` (offered by the document type's token cost, asked for by
270/// the transition's `$tokenPaymentInfo`) is acted on. Both values were
271/// carried but ignored up to v13, where the signer always paid. Batch
272/// transform v2 resolves one payer for the batch (`GasFeesPaidBy::resolve`)
273/// and reads the contract owner's balance into the action; batch advanced
274/// structure v1 refuses a request the document type does not offer
275/// (`GasFeesPaidByNotAllowedError`, 40129) or a batch naming two payers
276/// (`InconsistentGasFeesPaidByInBatchError`, 40130); `validate_fees_of_event`
277/// v1 judges the fee against the sponsor's balance, refusing an insisting
278/// batch unpaid when it falls short (`GasSponsorInsufficientBalanceError`,
279/// 40222) and handing a preferring one back to the signer; `execute_event`
280/// v1 charges whoever was admitted. The batch's signer only funds the
281/// principal, and its minimum balance pre-check v1
282/// (`identity_minimum_balance_pre_check`) asks no more of a batch that
283/// requests sponsorship. A failed batch is never sponsored, so check tx
284/// validates the state of a sponsored batch whose signer is under the fee
285/// minimum in full, on the first check and on every recheck (mempool
286/// policy, not consensus).
287/// 12. **Optional token costs**: a document type's token cost may declare
288/// `optional: true` (v3 meta-schema). A transition that leaves
289/// `$tokenPaymentInfo` out then pays no token and its signer pays the gas
290/// in credits, as on an action without a token cost (the base action
291/// transformer waives the cost, and no sponsorship applies). With the
292/// payment info present the token is charged exactly as for a required
293/// cost, and too small a token balance stays a rejection. Contracts up to
294/// v13 cannot carry the flag, so the waiver is inert before this version.
295/// 13. **Pre-programmed distribution amounts are bounded**:
296/// `TokenPreProgrammedDistribution::validate_amounts` rejects a release
297/// whose amounts total more than `i64::MAX` with the new
298/// `PreProgrammedDistributionAmountOverLimitError` (code 10277). It runs
299/// on contract create (`DRIVE_ABCI_VALIDATION_VERSIONS_V10`'s create
300/// `basic_structure` 2) and, for the tokens an update adds, on contract
301/// update (`CONTRACT_VERSIONS_V6`'s `validate_update` 1). A release is
302/// stored as a sum tree, so up to v13 such a create passed validation and
303/// failed inside Drive as an internal error: never paid for, and stripped
304/// from every proposal. An update failed the same way on a single amount
305/// over the limit (its fee estimation takes the insert path), but was
306/// accepted when only the total overflowed, since it wrote no distribution
307/// storage; from v14 it writes it (`update_contract` 2) and would fail.
308/// Tokens a contract already has are not judged, so a contract holding
309/// such a token stays updatable.
310/// 14. **Tokens of one contract sharing a pre-programmed release time**:
311/// `DRIVE_TOKEN_METHOD_VERSIONS_V2` bumps
312/// `add_pre_programmed_distributions` to 1, which queues the release-time
313/// tree the tokens share once instead of once per token. Queued twice,
314/// the batch is refused as an internal error by a node with
315/// `batching_consistency_verification` on; the default is off, and there
316/// GroveDB folds the identical inserts, so the stored state is unchanged
317/// and only the processing fee drops, by the existence read the later
318/// tokens no longer make.
319///
320/// 15. **Tokens added by a contract update are set up like registered ones**:
321/// `update_contract` v2 (`DRIVE_CONTRACT_METHOD_VERSIONS_V4`) creates the
322/// perpetual, pre-programmed and once-per-identity distribution storage
323/// of a token the update adds, and mints its base supply to the token's
324/// `newTokensDestinationIdentity`, or to the contract owner without one,
325/// with the total supply starting at the base supply. v1 did neither: a
326/// claim on such a token failed as an internal error, and the token sat at
327/// a total supply of zero with nobody holding any of it. Nothing is minted
328/// retroactively for a token an update added under an earlier version.
329///
330/// 16. **Contract moderation**: a data contract may declare, in its config,
331/// a banlist and/or a suspension list of identities and who edits them
332/// (the owner, or the owner and up to `SystemLimits::max_contract_moderators`
333/// named identities, each of which must exist). `CONTRACT_VERSIONS_V6`
334/// makes config V2 the config of every new contract (`max_version` and
335/// `default_current_version` 2), which carries
336/// the declaration; a contract create or update carrying a V2 config is
337/// inactive before this version (`StateTransition::active_version_range`).
338/// `DPP_VALIDATION_VERSIONS_V5.validate_config_update = 2` fixes the lists
339/// a contract keeps at its creation: an update turns none on and none off,
340/// and may only change the moderators.
341/// `ContractUserModeration` (state transition type 24, gated by
342/// `CONTRACT_USER_MODERATION_INITIAL_PROTOCOL_VERSION`) bans, unbans,
343/// suspends until a block time (at most
344/// `SystemLimits::max_contract_suspension_until`) and unsuspends one
345/// identity, signed by the owner or a moderator with a CRITICAL key; a
346/// ban and a suspension carry a reason, stored with the entry: a text of
347/// at most `SystemLimits::max_contract_moderation_reason_length` bytes,
348/// an optional code nothing checks, reserved for ban codes a contract may
349/// declare in a later version, and up to
350/// `SystemLimits::max_contract_moderation_reason_documents` documents the
351/// reason is about, named by type and id and not looked up. A contract may also keep a warning list
352/// (`[64, contract, 2] / 224`): a warn appends a warning, the block time and
353/// a reason, to the identity's entry, at most
354/// `SystemLimits::max_contract_warnings_per_identity` at a time, and a
355/// clearWarnings deletes the entry; warnings bar nothing and are what a
356/// status query and the identity's clients read;
357/// `DRIVE_ABCI_VALIDATION_VERSIONS_V10` turns its gates on, moves the
358/// contract update's basic structure to 2 and the contract create and
359/// update state validation (already 1 here) checks the named moderators.
360/// `batch_state_transition.contract_moderation_gate = Some(0)` makes the
361/// batch transformer refuse, paid, the document transitions of a banned or
362/// suspended signer, its deletions excepted (and its retractions, item 72),
363/// and collect a lapsed
364/// suspension, which
365/// `documents_batch_transition` 1 (`DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V4`)
366/// deletes when the batch executes; the same field gates the other
367/// party of a transfer or a purchase, so a barred identity neither
368/// receives nor sells a document. Token transitions are not gated.
369/// `DRIVE_CONTRACT_METHOD_VERSIONS_V4` bumps `insert_contract` to 2,
370/// which creates the list trees (`[64, contract, 2] / 128`, `/ 192` and `/ 224`, inside the contract's other tree), and
371/// adds the `moderation` method table; the verify and
372/// query tables gain the status and entries methods.
373///
374/// 17. **Document action fees and the contract fee claim**: a document type
375/// may charge a fixed fee in credits for an action on one of its documents
376/// (the `actionFees` keyword of the v3 document meta-schema, read by
377/// `try_from_schema` 3), split between the contract's owner pot and its
378/// moderators pot and priced as written or scaled by the fee multiplier of
379/// the epoch. The fees of a document type never change (document type
380/// `validate_update` 1), and a `moderators` part needs declared moderation
381/// (contract create and update basic structure 2). Whoever pays the gas
382/// pays the fee, the contract owner never into their own owner pot, and
383/// only for an action that executes: `validate_fees_of_event` 1 and
384/// `execute_event` 1 (`DRIVE_ABCI_METHOD_VERSIONS_V10`) settle the payer
385/// and move the credits with the batch's own operations, outside the fee;
386/// `apply_drive_operations` 1 merges every write of one identity balance,
387/// fee pot or prefunded specialized balance in a batch into one, so a fee
388/// leaving the balance a purchase price or a voting fund also leaves takes
389/// both, and refuses a batch writing one token balance or supply twice.
390/// Fee validation estimates for the payer it settles on and hands that
391/// payer to `execute_event` 1.
392/// `DRIVE_CONTRACT_METHOD_VERSIONS_V4` gains the `fee_pots` method table:
393/// the pots are sum items under two sum trees of the prefunded specialized
394/// balances (`[40, 64]` and `[40, 192]`), which `create_initial_state_structure`
395/// 4 and the upgrade to this version create, so they stay inside the total
396/// credits the platform checks every block, and the epoch each pot was
397/// last claimed in is an item of the contract's other tree (`32` and `96`).
398/// `ContractFeeClaim` (state transition type 25, gated by
399/// `CONTRACT_FEE_CLAIM_INITIAL_PROTOCOL_VERSION`) pays a pot out, at most
400/// once per epoch each: the owner pot to the contract owner, the moderators
401/// pot in equal shares to the moderation team, what the split leaves over
402/// staying in the pot. `DRIVE_ABCI_VALIDATION_VERSIONS_V10` turns its gates
403/// on, `DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V4` adds its converter, and
404/// the verify table gains `verify_contract_fee_pots`.
405/// 18. **Document ids commit to the identity contract nonce**: up to v13 a new
406/// document's id hashed the contract, owner, document type and the entropy
407/// of the create transition, and the create check only asks whether a
408/// document exists under the id right now. The owner of a deleted
409/// document could therefore create another one under the same id by
410/// reusing the entropy, with different content, and everything that
411/// referenced the id (a `refersTo` property, a like, a moderation removal
412/// record) then pointed at the new content, which defeats
413/// `documentsMutable: false` for a deletable document type.
414/// `DOCUMENT_VERSIONS_V4` sets `generate_document_id` to 1: the id also
415/// hashes a domain tag and the identity contract nonce of the create
416/// transition, which is consumed at most once, so an id can be produced
417/// at most once. The entropy stays in the hash (ids remain
418/// unpredictable) and on the wire (the transition format is unchanged);
419/// batch advanced structure validation 1, which only this version
420/// selects, recomputes the id through `Document::generate_document_id`
421/// and bills both passes of the double SHA-256 by the real preimage
422/// length (4 blocks for most document type names) where v13 bills a
423/// flat 2.
424/// Ids of documents created before the upgrade can not be produced by
425/// the new derivation either. A client that still derives the entropy
426/// only id has every create rejected with
427/// `InvalidDocumentTransitionIdError`. Every create path of the clients
428/// in this repository derives through `Document::generate_document_id`:
429/// `DocumentCreateTransitionV0::from_document` for dpp, rs-sdk and the
430/// bindings built on them, and in wasm-dpp2 the `DocumentCreateTransition`
431/// constructor (which also writes the id back onto the JavaScript
432/// `Document`), `Document.generateId` with its `identityContractNonce`
433/// argument, `setIdForCreation` and the `identityContractNonce`
434/// constructor option.
435/// 19. **Document deletion by moderators**: a document type of a contract
436/// that declares moderation may set `moderatorAbilities.delete` (meta-schema
437/// v3, fixed when the type is created, refused on a type that keeps
438/// history, is indexOnly or restricts creation; for references such a type
439/// is no longer permanent, so a permanentDocument reference refuses it, and
440/// a moderatedDocument or a deletableDocument reference takes it, see 64). A
441/// moderation declaration may then keep
442/// no list at all. `ContractUserModeration` gains the `DeleteDocument`
443/// action: the owner or a moderator deletes a document of such a type,
444/// except the owner's and the moderators' own, with a reason like a
445/// ban's. The deletion leaves a record under the contract
446/// (`[64, contract, 2] / 16 / <document type> / <document id>`: the
447/// document's owner, the moderator, the block time and the reason), paid
448/// for by the moderator and never deleted; `insert_contract` 2 creates
449/// the records tree of each such document type, `update_contract` 2 the
450/// tree of one an update adds, and either the tree above them with the
451/// contract's first. The deleted document's
452/// owner gets no storage refund: `apply_drive_operations = 1`
453/// (`DRIVE_VERSION_V9`) attributes the removal of a batch that carries
454/// the forfeiture to nobody, so the credits stay in the storage pools.
455/// A record is final, since a document id is produced at most once (18).
456/// Neither the type's deletion token cost nor its `actionFees` deletion
457/// fee is charged.
458/// The moderation method table, the verify table and the query table gain
459/// the document removal methods (`getContractDocumentRemovals`).
460/// `moderatorAbilities.deleteWithin` bounds the deletion in time: so many
461/// seconds after a document's last modification (`$updatedAt`, or
462/// `$createdAt` on a type whose documents never change; the type must
463/// require its clock), past which no moderator deletes it, the
464/// contract owner included (`DocumentModerationWindowElapsedError`); a
465/// document's own owner still deletes it as `canBeDeleted` allows. A
466/// replace opens the window again. Fixed with the type, like the flag.
467///
468/// 20. **Document transitions agree to their action fee**: version 2 of the
469/// document base transition, the default from this version
470/// (`STATE_TRANSITION_SERIALIZATION_VERSIONS_V3`) and inactive before it
471/// (`StateTransition::active_version_range`, since earlier software
472/// cannot decode it), carries an action fee agreement: the owner and moderators amounts the signer saw declared,
473/// which must match the document type's exactly, and for a fee priced by
474/// the fee multiplier the multiplier they knew with the increase, in
475/// percent, they accept. Batch advanced structure 1
476/// (`DRIVE_ABCI_VALIDATION_VERSIONS_V10`) refuses, as a paid nonce bump
477/// that charges no fee, an action that charges a fee without an agreement
478/// (40132), with one to other amounts or another pricing (40133), or
479/// whose epoch's multiplier rose beyond the tolerance (40134), so a
480/// contract whose fees change cannot make a signed transition pay them.
481/// Check tx judges the agreements again on every recheck, off the action
482/// the transformer rebuilt with the contract and the multiplier as they
483/// are then, so a batch a block would refuse leaves the mempool instead
484/// of failing there (mempool policy, not consensus).
485///
486/// 21. **Document restore by moderators**: the removal record a moderator's
487/// deletion leaves (19) also holds a double SHA-256 of the document as
488/// serialized under its type at the deletion (`ContractDocumentRemoval::
489/// document_hash`), and `ContractUserModeration` gains the
490/// `RestoreDocument` action: the owner or any current moderator brings
491/// the document back, as it was, within
492/// `SystemLimits::contract_document_restore_window_ms` (a week) of the
493/// removal. The bytes must decode under the type and hash to what the
494/// record holds; refused otherwise, or without a record (41119), past the
495/// window (41120), on a hash mismatch (41121), once restored (41122), or
496/// when another document took a value of one of the type's unique indexes
497/// meanwhile (40105). The document goes back through the ordinary insert,
498/// its storage flags naming its owner (the signer pays, the owner keeps
499/// the refund of a later deletion), and the record is marked restored in
500/// place (`ContractDocumentRemoval::restoration`: who, when) rather than
501/// deleted; a restored document deleted again gets a fresh record in place
502/// of the marked one, which the deletion transform reads to know. Neither
503/// the type's creation token cost nor its `actionFees` creation fee is
504/// charged, and no fee agreement is asked. `moderatorAbilities.delete` is
505/// now also refused on a type with a contested index, whose deletions
506/// could never be undone. The record grows on the wire
507/// (`getContractDocumentRemovals`: `document_hash`, `restoration`).
508///
509/// 22. **Elected moderation teams, the declaration and the interim**: a data
510/// contract may declare, when it is created, that its moderators are a team
511/// elected by masternodes and evonodes (`ContractModerators::Elected`, a third kind
512/// beside the owner and an appointed set, in the same config V2). The
513/// declaration is frozen: the join and vote windows (at most four weeks, at
514/// least one day on mainnet and 0 elsewhere, one week by default), in
515/// seconds and bounded by `SYSTEM_LIMITS_V4`;
516/// whether the seat can be contested again once a team is seated
517/// (`seatContestable`, required with no default), and for a contestable
518/// seat the challenge cool-down (`challengeCoolDown`, in seconds, two weeks
519/// to three years, refused on a seat that can not be contested; in Rust
520/// one `Option<u32>`), which nothing reads until challenges come after
521/// this version, a seat never being contested again here; an optional,
522/// unbounded election delay in seconds after the contract's creation
523/// before the first charter may be filed (`electionDelay`, read by the
524/// `moderation: "electionOpen"` reference requirement of item 24); how many
525/// members a seated team's leader may add after the election
526/// (`maxAddedModerators`, 0 when left out, at most
527/// `SYSTEM_LIMITS_V4.max_contract_moderation_added_moderators`, 15); the
528/// document types the team moderates, each with the abilities the seated
529/// team holds on it; who moderates until the first team is seated (the owner, an
530/// appointed set, or nobody, with the moderated types not yet usable or
531/// used unmoderated meanwhile); and whether the owner is protected from the
532/// team. `validate_moderation_config` v0 checks
533/// it against the contract's document types (10900), and
534/// `validate_config_update` 2 refuses every change to it, and entering or
535/// leaving elected moderation, with `DataContractConfigUpdateError`. The
536/// interim moderators moderate and claim the pot as the merged kinds do;
537/// with nobody named, nobody may claim the moderators pot, which
538/// accumulates for the team to come, and with the types not yet usable
539/// `contract_moderation_gate` v0 refuses, paid, every document transition
540/// of a moderated type (`ContractModeratedDocumentTypeNotYetUsableError`,
541/// 41200) until a charter is seated (item 40).
542///
543/// 23. **Contested indexes without a Lock choice, and ties to the earliest
544/// contender**: a contested unique index may declare `"resolution": 1`,
545/// `ContestedIndexResolution::MasternodeVoteNoLocking` (meta-schema v3,
546/// parser generation 3). Such a contest offers no Lock choice
547/// (`VoteChoiceNotAllowedForVotePollError`, 40307, from `validate_state` 1
548/// of the masternode vote) and always ends with a winner. Its end date is
549/// the end of the join window until a second contender joins, when
550/// `add_contested_document_for_contract_operations` 1 moves it to the full
551/// poll duration, removing the join window's end date when no other contest
552/// ends then, so a contest with a single contender is awarded without the
553/// vote window. `check_for_ended_vote_polls` 1 awards a tie to the
554/// **earliest** contender (creation time, block height, core height,
555/// document id) for every resolution, where the shipped rule awarded the
556/// latest; DPNS contests ending from this version on follow the new rule.
557/// Before reading the contests due, it removes any end date left with no
558/// contest among the first `maximum_vote_polls_to_process` due, since each
559/// would take a slot of that read and end nothing.
560///
561/// 24. **Contract references may require elected moderation, a minimum age, a
562/// minimum time since the last update, an owner relation to the writer or
563/// config flags of the referenced contract**: a `contract` `refersTo`
564/// declaration may carry `contractRequirements`, what the referenced
565/// contract must declare beyond existing, with `moderation: "elected"` or
566/// `"electionOpen"` (elected, and the contract's own `electionDelay` since
567/// its creation has passed, or it declares none),
568/// `minimumAgeSeconds` (the contract's recorded creation time must be at
569/// least that many seconds before the block time of the write),
570/// `minimumSecondsSinceUpdate` (the same of the later of its creation and
571/// last update times; a contract without a recorded creation time never
572/// meets either), `owner` (`"self"`: the contract is owned by the
573/// `$ownerId` of the referring document, `"other"`: by anyone else),
574/// `readonly: true` (its config is read-only, so it can never be updated
575/// again), `keepsHistory: true` (its config keeps history) and
576/// `ownerProtected` (its elected moderation declaration protects the owner
577/// from the team, or does not, as the value says; a contract without
578/// elected moderation meets neither value) as the requirements
579/// (meta-schema v3, `apply_property_reference` 0,
580/// `ContractReferenceRequirements` on
581/// `DocumentPropertyReferenceTarget::Contract`). The document reference
582/// validation checks them against the contract it fetched for the
583/// existence check and the write itself (its owner and block time), so
584/// they cost no further read, and refuses the first unmet requirement with
585/// `ReferencedContractRequirementNotMetError` (40135). A replace re-checks
586/// them when it changes the reference. `owner` is judged against the
587/// writer, which a transfer or a purchase changes without any write, so
588/// on a document type whose documents can be transferred or traded a
589/// declaration carrying it is re-checked, whole, on every replace, as a
590/// `$ownerId` writer gate is: the new owner has to repoint the reference,
591/// so registration refuses one held by an `immutable` property of such a
592/// type. The other requirements are facts about the referenced contract and
593/// never bring a reference back. A changed `contractRequirements` is an
594/// incompatible schema change on update.
595///
596/// 25. **Typed arrays of scalars in document schemas**: a document property
597/// may be `type: "array"` with an `items` element schema instead of
598/// `byteArray` (meta-schema v3, `parse_typed_array` 0,
599/// `DocumentPropertyType::TypedArray`). An element is an integer, a
600/// number, a string, a boolean, a byte array or an identifier; objects
601/// and arrays of arrays are refused. On the array `minItems` and
602/// `maxItems` count elements, `maxItems` is required (with `minItems`
603/// not above it) and at most `SYSTEM_LIMITS_V4.max_typed_array_items`
604/// (1024), and `uniqueItems` refuses a document repeating an element. An
605/// element's `enum` has members of the element type only (none on a byte
606/// array or identifier element), and an integer element's `minimum` and
607/// `maximum` are integers; the parser reads them so random documents stay
608/// inside them. The array is stored inline, a varint element count followed by the
609/// elements, each encoded exactly as a required scalar property of its
610/// type: an identifier element is 32 raw bytes, an integer element takes
611/// the width its bounds give it, a fixed-size byte array element is raw.
612/// A contract update may not change how an element encodes
613/// (`validate_update` 1). The array cannot be an index property or one
614/// side of a `propertyAgreement`. Its identifier and byte array elements
615/// are conversion paths (`find_identifier_and_binary_paths` 1). A byte array
616/// refuses `items`, and an identifier (a byte array with the identifier
617/// `contentMediaType`) now refuses `uniqueItems`, which would demand that
618/// no byte repeat.
619///
620/// 26. **Distinct identifier properties**: the `distinctFrom` property
621/// keyword (meta-schema v3, `apply_distinct_from` 0, `DistinctFrom` on
622/// `DocumentProperty`) requires an identifier property's value to differ
623/// from the value of a named property of the same document, or from the
624/// document's `$ownerId`; on the `items` of a typed array of identifiers
625/// it binds every element. A pure structure rule: document create
626/// structure validation 1 and replace structure validation 0 call
627/// `validate_distinct_from_properties` (`validate_distinct_from` 0) on the
628/// transition's data and owner id after the schema validation, transfer
629/// and purchase structure validation 0 call it on the stored document and
630/// its new owner (the three generation-0 modules were extended in place:
631/// the call is inert before this version, where no property carries the
632/// keyword), and each refuses an equal pair with
633/// `DocumentPropertyNotDistinctError` (10419); an absent named property
634/// passes. The parser checks the target at contract
635/// registration and update (it must exist, be an identifier and not be
636/// the declaring property), and a changed `distinctFrom` is an
637/// incompatible schema change on update.
638///
639/// 27. **`encryptedFor` on byte array properties**: a byte array property may
640/// declare how its ciphertext was produced, so wallets read the recipe
641/// from the contract instead of a side channel: `recipient` (an identifier
642/// property of the same document type, or `$ownerId`), `recipientKey` and
643/// `senderKey` (integer properties of the same type bounded to u32,
644/// carrying key ids) and `scheme` (`ecdh-secp256k1-aes256-cbc`, the
645/// dashpay contact request scheme: a 16-byte IV followed by AES-256-CBC
646/// with PKCS7 padding under the ECDH shared key). Meta-schema v3 admits it
647/// on byte arrays that are not identifiers, `apply_encrypted_for` 0 parses
648/// it onto `DocumentProperty::encrypted_for` and checks the three named
649/// properties exist with the right types at registration. Document create
650/// structure validation 1 and replace structure validation 0 (extended in
651/// place, inert before this version) call
652/// `validate_encrypted_property_shapes` (`validate_encrypted_property_shapes`
653/// 0, `None` before this version) to check the ciphertext shape of every declared property a transition supplies,
654/// at least the IV plus one block and a multiple of the block, and refuse
655/// it with `InvalidEncryptedPropertyShapeError` (10420). Nothing else about
656/// the ciphertext is verifiable on chain. A changed `encryptedFor` is an
657/// incompatible schema change on update.
658///
659/// 28. **Property and document type names are word characters only**:
660/// meta-schema v3 refuses `-` in a property name (top-level or nested,
661/// and in the property paths of `refersTo` declarations) and generation
662/// 3 of the document type parser refuses it in a document type name,
663/// under full validation. Every earlier meta-schema and generation
664/// admitted `-`, which the dotted and `list[]` path syntax was never
665/// written for; a census of every contract create and update on mainnet
666/// and testnet (2026-09-23) found no name carrying one, so nothing stored
667/// is affected. Stored contracts are read as they are.
668///
669/// 29. **Identity key references may require a purpose and a document type
670/// bound**: an `identityPublicKey` `refersTo` declaration may carry
671/// `keyRequirements`, what the referenced key must be beyond existing and
672/// not being disabled, with `purpose` (the key's purpose, by its wire name,
673/// any but `system`) and `boundTo` (the key's contract bounds must be
674/// exactly the declaring contract and the named document type of it) as
675/// the requirements (meta-schema v3, `apply_property_reference` 0,
676/// `IdentityKeyReferenceRequirements` on
677/// `DocumentPropertyReferenceTarget::IdentityPublicKey`).
678/// `create_document_types_from_document_schemas` 1, edited in place (the
679/// check is inert before this version, where no parsed reference carries
680/// requirements), refuses a contract whose `boundTo` names a document type
681/// it does not have or one no key of the required purpose can be bound
682/// to, so the check never needs a second contract fetch and a declared
683/// requirement can be met. The document reference validation
684/// checks the requirements against the key it fetched for the existence
685/// check, so they cost no further read, and refuses the first unmet one
686/// with `ReferencedIdentityKeyRequirementNotMetError` (40136). A changed
687/// `keyRequirements` is an incompatible schema change on update.
688///
689/// 30. **Key references on the key id property**: an `identityPublicKey`
690/// `refersTo` declaration may sit on the key id property itself, an
691/// integer with `minimum` 0 and `maximum` 4294967295 (a `KeyID` is a
692/// `u32`), naming through `identityProperty` whose key the value is:
693/// `"$ownerId"` (the writer), `"$creatorId"` (the document's creator,
694/// only on a document type that records creator ids) or the path of an
695/// identifier property of the same document type (which must exist, be
696/// an identifier and not carry an `identityPublicKey` reference of its
697/// own); the last two are checked at contract registration (40125). The
698/// declaration takes no `keyIdProperty`; the identifier form is unchanged
699/// and every other `refersTo` form stays identifier-only (meta-schema v3,
700/// `apply_property_reference` 0, `DocumentPropertyType::KeyIdWithReference`
701/// over `KeyReferenceIdentityProperty`). At document create and replace the
702/// reference validation reads the key id from the property, resolves the
703/// identity (the writer, the creator the action carries, or the named
704/// property's value; a key id set while that property is unset, or on a
705/// document that records no creator, one written before its type recorded
706/// creator ids, being refused with 40125) and fetches that key, so the key
707/// fetch is the only read; a key that does not exist refuses the write,
708/// paid, with
709/// `ReferencedIdentityKeyNotFoundError` (40123) and a disabled one with
710/// `ReferencedIdentityKeyDisabledError` (40124), as for the identifier
711/// form. A replace re-validates `$ownerId` touched or not, as the
712/// `$ownerId` writer gate is, since the writer may not be the one who
713/// wrote the key id; `$creatorId` when the key id changed; a property
714/// path when the key id or that property changed (a transfer itself is
715/// never checked: the reference governs writing, not holding). A
716/// `keyIdProperty` may not name a property carrying this form (40125 at
717/// registration). `keyRequirements` (item 29) sit on this form exactly
718/// as on the identifier form, checked by the same key check and by the
719/// same `boundTo` registration rule. Adding it to, removing it from or
720/// changing it on an existing property is an incompatible schema change
721/// on update, like the rest of a `refersTo`; a property an update adds
722/// may carry it, so a `$creatorId` one can meet documents written before
723/// their type recorded creator ids.
724///
725/// 31. **`refersTo` on the elements of a typed array**: an identifier element
726/// of a typed array may carry a `refersTo` declaration on its `items`,
727/// which every element then declares (meta-schema v3 `documentArrayItem`
728/// reuses the property `refersTo` definition by `$ref` and refuses
729/// `identityPublicKey` in both forms, which pair one key id with the
730/// reference).
731/// `parse_typed_array` 0 folds it into the element through the same
732/// `apply_property_reference` 0 a scalar identifier goes through, so the
733/// element is `IdentifierWithReference(target)` inside `item_type`, and
734/// `DocumentPropertyType::reference` reports either kind. Contract
735/// registration (`data_contract_reference_validation` 0) checks the
736/// declaration as a single one, and document create state validation 2
737/// and replace state validation 1 (`document_reference_validation` 0,
738/// extended in place: both are only reached from protocol version 14,
739/// where the element arm is the only new path) check every element as a
740/// single reference, refusing the first that fails with that
741/// reference's error (40120, 40127, 40135 and the rest), its path the
742/// element's list path (`reasons[2]`). A replace re-validates the
743/// elements of a changed list the stored list did not hold (the replace
744/// action carries `stored_changed_values`), and all of them when a
745/// property bound by a `propertyAgreement` changed, for a `$ownerId`
746/// agreement or for `deletableDocument` elements. A repeated element and
747/// a foreign contract holding the referenced document type are fetched
748/// once per list. Registration caps the references one document
749/// can carry at `SYSTEM_LIMITS_V4.max_references_per_document` (256; one
750/// per property declaring a reference, key id references of item 30
751/// included, `maxItems` per typed array of referencing elements;
752/// backfilled into the earlier tables), and
753/// refuses an `immutable` property holding a `deletableDocument`
754/// reference no replace could clear (a typed array of them, or a single
755/// one inside an immutable object), which could never be replaced once
756/// a target is deleted, and a single top-level one frozen only under a
757/// condition (see 66), which a replace could clear once its target is
758/// deleted and a later one the condition leaves free set to another
759/// document. A changed
760/// element `refersTo` is an incompatible schema change on update.
761///
762/// 32. **Document references resolved through a unique index**: a
763/// `permanentDocument` `refersTo`, on an identifier property or on the
764/// elements of a typed array (item 31), may carry a `lookup`
765/// (meta-schema v3, `apply_property_reference` 0, parsed to the appended
766/// `DocumentPropertyReferenceTarget::PermanentDocumentLookup`, so an id
767/// reference keeps its variant and its encoding): the value is then
768/// not the referenced document's id, and the referenced document is the
769/// one the named unique index of the referenced document type finds for
770/// a key assembled from the referring document. `keys` maps every index
771/// property to a property path of the referring type, `$ownerId` or `.`
772/// (the value, or the element, exactly once). A `deletableDocument`
773/// reference may take one too (`DeletableDocumentLookup`, appended): it
774/// then means a document with this key exists now, since the key may find
775/// a later document once the one it found is deleted, so every replace
776/// re-validates it, an immutable property may not hold it, and it is the
777/// one deletable form a reference expression and `ownerRefersTo` (never
778/// `creatorRefersTo`) take. Generation 3 of the parser
779/// checks on every parse that each property a key reads is a stored,
780/// required, single value of the referring type;
781/// `create_document_types_from_document_schemas` 1, edited in place like
782/// for item 29 (inert before this version, where no parsed reference
783/// carries a lookup), checks a lookup into a document type of the same
784/// contract under full validation (the index exists, is unique, carries
785/// no `timeRange` and is not on an indexOnly type, the keys cover it
786/// exactly, every source shares its index property's value kind, and the
787/// key cannot move off the document it found: its schema properties are
788/// immutable, none an optional `deletableDocument` reference by id, which
789/// a replace may clear once its document is deleted (item 73), and
790/// `$ownerId` is only a part on a type that is neither transferable nor
791/// tradeable), and the contract reference validation
792/// checks one into another contract, refusing it with
793/// `ReferencedDocumentLookupInvalidError` (40137). The document
794/// reference validation (generation 0, reached only from this version)
795/// queries the index for each value's key, billed as a document fetch,
796/// refuses a write with no match with `ReferencedEntityNotFoundError`
797/// (40120, an element named by its list path), checks a
798/// `propertyAgreement` against the document found, and on replace
799/// re-validates when a property the key reads changed. A key may read
800/// `$ownerId` only on a referring type that is neither transferable nor
801/// tradeable, checked on every parse. A changed `lookup` is an
802/// incompatible schema change on update. Chained queries and composite
803/// by-id joins refuse a lookup reference as a join property, and
804/// preallocated indexes are never bound through one.
805/// 33. **Reference expressions (`anyOf` / `allOf`)**: a `refersTo`, on an
806/// identifier property or on the elements of a typed array (item 31), may
807/// be `{ "anyOf": [operand, ...] }`, holding if at least one operand
808/// holds, or `{ "allOf": [operand, ...] }`, holding if every operand holds
809/// for the same value, in place of one target (meta-schema v3, which
810/// admits either combinator only as the declaration's one key,
811/// `apply_property_reference` 0, parsed to the appended
812/// `DocumentPropertyReferenceTarget::AnyOf` and `AllOf`, so every single
813/// target keeps its variant and its encoding; decoding refuses a nesting
814/// deeper than `MAX_REFERENCE_EXPRESSION_DECODE_DEPTH`, 16, so the bytes of
815/// a consensus error cannot recurse without bound). An operand is a leaf,
816/// an `identity`, a `permanentDocument` (by id or with a `lookup`, item
817/// 32), a `listElement`, a `deletableDocument` with a `lookup` (which
818/// re-validates the expression on every replace), or an expression of the
819/// other combinator; a list names two or more operands. `contract`,
820/// `token`, `deletableDocument` by id and
821/// `identityPublicKey` leaves, the key id form, a combinator directly
822/// inside the same combinator and keys beside a combinator are refused on
823/// every parse. Registration caps a list at
824/// `SYSTEM_LIMITS_V4.max_reference_operands` (4) and the nesting at
825/// `max_reference_expression_depth` (4 combinators on any path to a leaf),
826/// both backfilled into the earlier tables, refuses two alike operands of
827/// one list (a leaf naming the declaring contract explicitly counting as
828/// the one omitting it), counts every leaf against
829/// `max_references_per_document`, and checks each leaf as the same
830/// declaration alone (`create_document_types_from_document_schemas` 1 and
831/// `data_contract_reference_validation` 0, both walking
832/// `DocumentPropertyReferenceTarget::leaves_with_paths`, which is the
833/// declaration itself at an empty path for a single target, so their
834/// output is unchanged where no expression can parse), a failing leaf
835/// named by where it sits (`resignation.memberId.anyOf[1].allOf[0]`). The
836/// document reference validation (`document_reference_validation` 0,
837/// reached only from this version) evaluates each value operand by operand
838/// in declared order: an `anyOf` stops at the first operand that holds and
839/// otherwise refuses with the last operand's error, an `allOf` stops at the
840/// first that fails and refuses with its error, so a refusal is always a
841/// leaf's own error and no new error exists; every read is billed, the
842/// failed operands' included. A `propertyAgreement` belongs to its leaf and
843/// is checked only against that leaf's document. A replace re-validates an
844/// expression when its value, or a property one of its leaves binds,
845/// changed. A changed expression is an incompatible schema change on
846/// update. Chained queries and composite by-id joins refuse an expression
847/// join property, and preallocated indexes are never bound through one.
848/// 34. **References on the document's writer or creator (`ownerRefersTo`,
849/// `creatorRefersTo`)**: a document type may declare one `refersTo`
850/// declaration of its own, under the doctype-level `ownerRefersTo`
851/// keyword (meta-schema v3, which reuses the property declaration by
852/// `$ref`), whose value is the document's `$ownerId`, the writer, instead
853/// of a property's: a single target, or a reference expression (item 33)
854/// whose every leaf is one of the targets that can hold a writer:
855/// `identity`, and a `permanentDocument` found through a `lookup`, where
856/// `.` is the writer (and, for the writer alone, a `deletableDocument`
857/// found through one, item 32); `contract`, `token` and a document by id (which the
858/// writer's identity id never is) and `identityPublicKey` (which needs a
859/// key id) are refused, as a leaf too. Parser generation 3 reads it from
860/// the stored schema once the core parse has run the meta-schema, on
861/// every parse, through the same `apply_property_reference` 0 an
862/// identifier property's goes through, onto
863/// `DocumentTypeV2::owner_reference`, and refuses it on a type whose
864/// documents can be transferred or traded, since neither is a write. Every
865/// enumeration of a type's references goes through
866/// `DocumentTypeRef::reference_declarations`, which yields it first: its
867/// lookup's referring side is checked on every parse, a lookup into a
868/// type of the same contract by
869/// `create_document_types_from_document_schemas` 1 (edited in place like
870/// for item 29, inert before this version, whose parsers never set an
871/// owner reference), and the whole declaration at registration by the
872/// contract reference validation (`data_contract_reference_validation` 0,
873/// extended in place, only reached from this version), which names it
874/// `<documentType>.$ownerId` and lets its `propertyAgreement` name the
875/// writer on the referring side. It counts one against
876/// `max_references_per_document`. Document create state validation 2 and
877/// replace state validation 1 (`document_reference_validation` 0, extended
878/// in place, both only reached from this version) check the writer against
879/// the target exactly as a property's value is checked: on every create,
880/// and on a replace under the rules of its target (a changed property its
881/// lookup or a `propertyAgreement` reads, every replace for a `$ownerId`
882/// pair), and refuse the write with the error the target reports for a
883/// property (40120 and the rest) at the path `$ownerId`; an `identity`
884/// target fetches nothing, the transition having proved the writer exists.
885/// Adding, removing or changing it is an incompatible schema change on
886/// update (`validate_schema_compatibility` 1 freezes it as the shared rule
887/// set freezes `refersTo`). Its counterpart for a type whose documents can
888/// be transferred or traded is `creatorRefersTo`, whose value is the
889/// document's `$creatorId`, the creator, which never changes: the same
890/// two targets (`.` the creator), only on a type that records creator ids
891/// (`should_use_creator_id`: a transferable or tradeable type of a
892/// format-1 contract), so a type declares at most one of the two; stored
893/// as `DocumentTypeV2::creator_reference`, enumerated second by
894/// `reference_declarations`, named `$creatorId` (and
895/// `<documentType>.$creatorId` at registration), checked against the
896/// writer on a create and the stored creator on a replace under the same
897/// rules, never on a transfer or a purchase, and frozen on update the same
898/// way.
899/// 35. **References to an element of a list of a referenced document**: a
900/// new `refersTo` target, `listElement` (meta-schema v3,
901/// `apply_property_reference` 0, parsed to the appended
902/// `DocumentPropertyReferenceTarget::ListElement`, so every earlier
903/// variant keeps its encoding), on an identifier property, on the
904/// elements of a typed array (item 31), as a leaf of a reference
905/// expression (item 33), or on the writer or the creator (item 34, whose
906/// identity then must be listed; a third target those two take next to
907/// `identity` and a `permanentDocument` lookup, since an identity id can
908/// be an element of a list of identities): the value must be an element
909/// of the typed array
910/// of identifiers `inList` held by one document of `documentType`, the
911/// document whose `$id` the `propertyAgreement` pair with `$id` on the
912/// referenced side reads from an identifier property of the referring
913/// type (stored, optional or not; generation 3 of the parser checks it
914/// under full validation). `$id` joins `$ownerId` and `$creatorId` as a
915/// referenced-side agreement name for every document reference. In every
916/// other respect a list element is a document reference: `contractId`,
917/// `documentType` and its other agreement pairs are checked at
918/// registration as a `permanentDocument`'s are (the type must forbid
919/// deletion), and the list must be a stored typed array of identifiers
920/// fixed once a document is written (the type is immutable or lists the
921/// list's top-level property under `immutable`).
922/// `create_document_types_from_document_schemas` 1, edited in place like
923/// for items 29 and 32 (inert before this version, where no parsed
924/// reference is a list element), checks a list in the same contract
925/// under full validation, and the contract reference validation checks
926/// one in another contract, refusing it with
927/// `ReferencedDocumentListInvalidError` (40138). The document reference
928/// validation (generation 0, reached only from this version) fetches the
929/// list's document by the `$id` pair's value, once per write and shared
930/// with any other reference of the same document (every by-id document
931/// fetch of one write is now memoized), checks the other pairs against it,
932/// and refuses a value the list does not hold, or one set while the `$id`
933/// property is not, with `ReferencedEntityNotFoundError` (40120, the list
934/// element declaration as its entity type, an element named by its list
935/// path); the list is collected once, each value a set lookup. A replace
936/// checks it again when its value or a referring side of any pair
937/// changed, as every agreement is. Each value counts against
938/// `SystemLimits::max_references_per_document` like every other
939/// reference. A changed `listElement` is an incompatible schema change on
940/// update.
941///
942///
943/// 36. **Transient properties are never stored**: a transient property is
944/// judged on the transition and dropped before its document is stored.
945/// Up to v13 only a create dropped it and a replace stored whatever it
946/// carried; `document_from_replace_transition_action` 1 (paired with the
947/// contract-version stamp, edited in place, only selected by this
948/// version) drops the transient values of a replace by top-level name as
949/// a create does. The rules that read a stored value refuse a transient
950/// one, by the property's path and every enclosing object's
951/// (`is_transient`): at registration (parser generation 3 under full
952/// validation) every `transient` entry must name a top-level property,
953/// since Drive drops values by top-level name, and no index may read a
954/// transient property, which every document would leave in the index's
955/// null branch; a lookup's referenced side refuses such an index too
956/// (`referenced_side_error`); the contract reference validation
957/// (`data_contract_reference_validation` 0, extended in place, only
958/// reached from this version) refuses a `propertyAgreement` whose
959/// referenced property is transient, which no stored document carries,
960/// and a key reference that stores the key id while its identity is
961/// transient, in either form (`identityProperty` on the key id,
962/// `keyIdProperty` on the identity). A transient referring side of an
963/// agreement stays allowed: it is a write gate, judged on the
964/// transition. Changing the `transient` list on contract update was an
965/// unsupported keyword to the schema compatibility check, an internal
966/// error that dropped the transition unpaid; `validate_schema_compatibility`
967/// 1 freezes the set of names it lists (sorted and deduplicated before
968/// the diff, so a reordering is no change) as it freezes `refersTo`, an
969/// incompatible schema change.
970/// A census of every mainnet and testnet contract (2026-09-23) found
971/// `transient` only on DPNS-shaped `domain` types, which are immutable,
972/// index no transient property and list top-level properties only.
973///
974/// 37. **The moderation charters system contract**
975/// (`SystemDataContract::ModerationCharters`, schema v1, the first piece of
976/// decentralized moderation teams) carries seven document types, all
977/// immutable, the four a charter is made of undeletable and the three team
978/// changes deletable. A `reason` is a ground for a moderation
979/// action, keyed by its owner and a three-letter `code` unique among the
980/// owner's reasons. A `submittedCharter` is a leader's proposal to
981/// moderate one contract on that contract's own terms: its
982/// `targetContractId` refers to a contract declaring elected moderation
983/// (item 24, `moderation: "elected"`, so teams form during the contract's
984/// election delay), its `reasons` are a typed array (item 25) of
985/// references to reasons (item 31), and it carries an optional
986/// `moderatorsShare` and a `rewardSplit`. A `joinRequest` is an identity's
987/// offer to serve on a proposal, one per identity per proposal, whose
988/// `recipientId` must be the proposal's owner (`propertyAgreement`) and
989/// name a decryption key bound to `submittedCharter` (item 29), whose
990/// `senderKeyId` is an encryption key of the writer bound to `joinRequest`
991/// (item 30) and whose `encryptedMessage` declares its envelope (item 27).
992/// An `electedCharter` is a proposal put to the vote with its team: only
993/// the proposal's owner may create one, for the proposal's own target
994/// (`propertyAgreement`), its `targetContractId` requires
995/// `moderation: "electionOpen"`, and its `members` are identities each of
996/// which filed a join request for that proposal (item 32, a lookup through
997/// the join request's unique index) and none of which is the leader
998/// (item 26). Once a charter is seated, its leader adds members from the
999/// same join requests (`addedModerator`, the same lookup) and takes them
1000/// back by deleting the addition, and removes elected members
1001/// (`removedModerator`, whose `memberId` is a `listElement` of the
1002/// charter's `members`), putting one back by deleting the removal; each
1003/// exists at most once per member and charter (unique indexes), so the
1004/// team that acts is the leader plus the elected members less the
1005/// removals plus the additions (`ElectedCharter::active_members`). A
1006/// member asks to leave with a deletable `resignationRequest`, which only
1007/// a member may file (`ownerRefersTo` with an `anyOf` of a `listElement`
1008/// into the elected charter's `members` and a `deletableDocument` lookup
1009/// of an `addedModerator`, items 32 to 35) and which carries a message
1010/// encrypted to the leader; the leader acts on it by deleting the addition
1011/// or removing an elected member. The cap on
1012/// additions, the target's `maxAddedModerators`, is a consensus rule of
1013/// item 40.
1014/// Its `byTargetContract` index is a contested unique index
1015/// with `"resolution": 1`, the masternode vote without a Lock choice of
1016/// item 23, so an elected charter create opens or joins the contest for
1017/// its target. `SYSTEM_DATA_CONTRACT_VERSIONS_V3` registers it
1018/// (`moderation_charters: 1`). A proposal holds no rule beyond its schema:
1019/// the reward split sums to 100 through the contract's
1020/// `propertyConstraints` rule (item 39), so 11001 is never produced, and
1021/// the description fits 4096 bytes through the schema's own `maxBytes`
1022/// (item 38); every document validation checks both. Genesis registers it
1023/// on chains born at this version (`create_genesis_state` v1, behind the
1024/// app-connect branch), `transition_to_version_14` inserts it on upgrade,
1025/// and the Drive system contract cache serves it from this version
1026/// (`MODERATION_CHARTERS_CONTRACT_INITIAL_PROTOCOL_VERSION`). Item 40 seats
1027/// the winning team.
1028///
1029/// 38. **`maxBytes` on strings**: a property keyword for the bound plain JSON
1030/// Schema cannot count, the most UTF-8 bytes a string may take
1031/// (`maxLength` counts characters, which are up to four bytes each). It
1032/// goes on a string property, or on the `items` of a typed array of
1033/// strings where it bounds every element, and is 1 to 65535 and no lower
1034/// than `minLength`, checked at registration. Meta-schema v3 admits it and
1035/// `apply_max_bytes` 0 folds it into `StringPropertySizes::max_bytes`, so
1036/// `max_byte_size`, `max_size` and random documents respect it. The
1037/// document validation (`DataContract::validate_document_properties` 0,
1038/// extended in place, inert before this version) calls
1039/// `validate_max_bytes_properties` (`validate_max_bytes` 0, `None` before
1040/// this version) after the JSON schema, on every create and replace and in
1041/// every client that validates a document, and refuses a longer value with
1042/// `DocumentPropertyMaxBytesExceededError` (10421, naming the element as
1043/// `tags[2]` for an item). On update it moves like `maxLength`: it may be
1044/// raised or removed, not added or lowered. The moderation charters
1045/// contract (item 37) declares it on the proposal's description, replacing
1046/// the charter-specific description check, its error 11002 and
1047/// `SystemLimits::max_moderation_charter_description_length`.
1048///
1049/// 39. **Property constraints**: the doctype-level `propertyConstraints`
1050/// keyword (meta-schema v3, `parse_property_constraints` 0) names rules a
1051/// document's properties must meet, each a condition: a comparison
1052/// (`equal`, `notEqual`, `lessThan`, `lessThanOrEqual`, `greaterThan`,
1053/// `greaterThanOrEqual`) of two integer expressions built from integer
1054/// literals, paths of integer or boolean properties (a boolean reading as 1
1055/// for true and 0 for false), `add`, `subtract`, `multiply`, `divide`,
1056/// `modulo` and `power`, `min` and `max` over two or more operands and
1057/// `abs` over one, and sizes: `length` and `byteLength`, the characters and
1058/// UTF-8 bytes of a string property, and `count`, the items
1059/// of an array or byte array property, each 0 for a property the document
1060/// leaves out, `countPresent`, how many of two or more distinct properties
1061/// of any type the document holds, each as `present` tests it, so a rule
1062/// bounds how many of a group are set, and the system times and heights `$createdAt`, `$updatedAt`
1063/// and `$transferredAt` (block times in milliseconds), each also with
1064/// `BlockHeight` or `CoreBlockHeight` appended, of the document's creation,
1065/// last update (create, replace, price update) and last transfer (create,
1066/// transfer, purchase), which a rule may read only on a type listing them
1067/// in `required`; `in`, whether an integer expression takes one of two or
1068/// more distinct integer values; `equal` or `notEqual` of a string property
1069/// and a `{ "const": string }` or of two bare paths naming string
1070/// properties, or `in` of a string property and two or more distinct
1071/// strings, a string the document leaves out equalling no constant and no
1072/// other string unless an `ifAbsent` gives it a string default
1073/// (`{ "ifAbsent": ["status", "open"] }`, whose default an `enum` must list
1074/// too); `equal`, `notEqual` or `in` of an identifier property (one
1075/// declaring `refersTo` included) or of `$ownerId`, the document's owner,
1076/// likewise, with base58 identifier constants or another identifier operand
1077/// and no default, an identifier the document leaves out equalling none;
1078/// `startsWith` or `endsWith`, whether a string (a constant or a string
1079/// property, at least one a property) starts or ends with another, byte for
1080/// byte; `contains`, whether a typed array property holds an element equal
1081/// to an integer expression, a string or an identifier operand (a constant,
1082/// a property, or `$ownerId`), as its elements are, an array the document
1083/// leaves out holding nothing; `present` or `absent` naming a property of
1084/// any type, whether the document holds it (the one way to tell a property
1085/// left out from one set to 0); `anyOf` or `allOf` over two or more
1086/// conditions; `not` over one; `ifThen` over two (the second holding
1087/// whenever the first does, evaluated only then) or `ifThenElse` over three
1088/// (the second when the first holds, the third when it does not, only the
1089/// branch taken evaluated), no two alike; `notIn`, an `in` negated in as
1090/// many nodes. In an operand, a property the document leaves out counts as
1091/// 0, or as the value of an `ifAbsent` operand naming it. `countOf` and
1092/// `sumOf` operands read a total from state: how many documents of a type
1093/// of the same contract match a filter (keys of that type or `$ownerId`,
1094/// values read from the document written), or an integer property's total
1095/// over them, as the count or sum tree will keep it once the write is done;
1096/// the batch transformer reads them into the action
1097/// (`Drive::fetch_property_constraint_aggregate`, billed; in place in
1098/// transformer 0, reading nothing before this version), a transfer or
1099/// purchase reads again those depending on the owner, a price update those
1100/// of the rules it judges, and a rule reading one it is not given is not
1101/// judged by an SDK pre-check and an error in consensus, which reads them
1102/// all.
1103/// Arithmetic is exact `i128`: `divide` and `modulo` are Euclidean (the
1104/// remainder is never negative), and an overflow, a zero divisor, a
1105/// negative exponent or a value that is not an integer refuses the document
1106/// rather than wrapping. Conditions are checked in declared order and no
1107/// further than the outcome needs (`anyOf` stops at the first that holds,
1108/// `allOf` at the first that fails), a fault in one that is checked refuses
1109/// the document whatever the others say, and `not` never turns a fault into
1110/// a pass, so an earlier condition guards a later one. The parser checks
1111/// that every path an operand reads names an integer or boolean property,
1112/// every path a `length` or `byteLength` measures a string property, every
1113/// path a `count` counts an array or byte array property, every string
1114/// `startsWith` or `endsWith` tests a string property (a constant tested
1115/// against one with an `enum` starting or ending one of its values), every
1116/// array a `contains` looks in a typed array of the kind it looks for (a
1117/// string constant in the elements' `enum` when they declare one), every
1118/// system time or height a rule reads one the type lists in `required`
1119/// (none on an indexOnly type), every path compared with identifiers an
1120/// identifier property, every path compared with strings a string property
1121/// (whose `enum`, if it declares one, lists every constant it is compared
1122/// with), and every path `present`, `absent` or `countPresent` tests a
1123/// property of any type, none transient nor inside a transient object; that every
1124/// comparison and `in` reads a property or the owner; that nothing is
1125/// compared with itself; that strings and identifiers are only compared for
1126/// equality, and never with each other; that no `in` lists a value twice
1127/// and no `countPresent` a path twice;
1128/// that an `anyOf` or `allOf` holds none directly of its own kind and a
1129/// `not` no `not` or `notIn`; that an indexOnly type, whose deletes carry
1130/// no owner, reads no `$ownerId`; and that no condition or operand nests
1131/// deeper than
1132/// `MAX_PROPERTY_CONSTRAINT_PARSE_DEPTH` (64), on every parse. Under full
1133/// validation it holds the limits `SystemLimits::max_property_constraints`
1134/// (16 rules) and `max_property_constraint_nodes` (32 per rule, every
1135/// comparison, `in`, listed value, `const`, presence test and logical
1136/// operator counting as one, a `countPresent` as one plus one per path), and that no `anyOf` or `allOf` lists the same
1137/// condition twice, and at most `max_property_constraint_aggregates` (4)
1138/// distinct totals per type; once every type is parsed, that a tree keeps
1139/// each total (`documentsCountable` or `documentsSummable`, or an index
1140/// whose properties are exactly the filter's keys) and that no type with a
1141/// contested index totals its own documents, in
1142/// `create_document_types_from_document_schemas` 1, in place and inert
1143/// before this version. `DataContract::validate_document_properties` 0
1144/// (extended in place, inert before this version, and taking the document's
1145/// owner for `$ownerId`) calls `validate_property_constraints`
1146/// (`validate_property_constraints` 0) after the schema validation, so
1147/// document create and replace, and any client validating a document,
1148/// refuse a broken rule with `DocumentPropertyConstraintViolatedError`
1149/// (10422), naming the rule and why. A transfer and a purchase, which give
1150/// the document a new owner, are judged against the rules reading
1151/// `$ownerId` or the transfer's time and heights, with the new values, and
1152/// a price update, which sets the update's time and heights, against the
1153/// rules reading those (`validate_property_constraints_for_system_change`,
1154/// in their structure validation, in place and inert before this version;
1155/// the price update's call is new there). `validate_document_properties`
1156/// takes the document version's system values (`DocumentSystemValues`):
1157/// consensus gives the writer and the block's time and heights on create,
1158/// and on replace the stored creation and transfer values with the block's
1159/// as the update. The rules change nothing stored and read no state but
1160/// their totals. They
1161/// are fixed when the document type is created: a changed
1162/// `propertyConstraints` is an incompatible schema change on update. The
1163/// moderation charters contract declares its first one: a
1164/// `submittedCharter`'s `rewardSplit` members add up to 100, replacing the
1165/// charter-specific check, whose error 11001 keeps its place in
1166/// `BasicError` but is never produced.
1167///
1168/// 40. **Elected moderation teams moderate from their stored charter**: seating
1169/// writes nothing. Awarding the contest of item 37 writes the winning
1170/// `electedCharter`, the only one ever stored for its target, so the
1171/// charter seated on an elected contract is the one the charter contract's
1172/// `byTargetContract` index finds, and the moderation paths read it, each
1173/// read a billed document query of the system contract. Once one is seated,
1174/// only its team moderates the contract: the leader (the charter's owner)
1175/// and the active members (its `members` less removals, plus additions),
1176/// each alone, found by one point read of the unique `removedModerator`
1177/// index for an elected member or of `addedModerator` for anyone else; the
1178/// interim moderators
1179/// are refused (41101). The team holds the abilities the declaration gives
1180/// it: a deletion or restore needs `deleteDocuments` on the type, a list
1181/// action the ability on some moderated type
1182/// (`ContractModerationAbilityNotGrantedError`, 41201). The leader and the
1183/// active members are protected (41102), with the owner when the
1184/// declaration says so, and the interim moderators no longer are. A
1185/// `notYetUsable` interim stops blocking the moderated types
1186/// (`contract_moderation_gate` v0). An `addedModerator` past the target's
1187/// `maxAddedModerators` additions the charter holds is refused,
1188/// paid (`ModerationCharterAddedModeratorLimitReachedError`, 41202), by a
1189/// hook in the batch's `validate_state` v0 that only a create of the
1190/// charter contract reaches. A document action on a moderated type may
1191/// agree to the seated proposal's `moderatorsShare` of the declared
1192/// moderators part (rounded down) instead of the whole, and is charged
1193/// that: the batch transformer (state v2) reads the charter and its
1194/// proposal only for such an agreement, and advanced structure validation
1195/// and every recheck judge it (`DocumentActionFeeModeratorsShareMismatchError`,
1196/// 40139, for any other lower amount or with no seated charter). The
1197/// interim team's claim of the moderators pot is refused once a charter is
1198/// seated (41113). No table moves: every generation involved is unreleased,
1199/// but for the shipped batch `validate_state` v0, which no batch of an
1200/// earlier version reaches through the new hook.
1201///
1202/// 41. **A seated team's pot, action counts and reasons**: the leader or an
1203/// active member of a seated team claims the moderators pot for the team,
1204/// and it is split by the proposal's `rewardSplit`: the leader share to the
1205/// leader, the equal share between the other members (the leader's when it
1206/// has none), and the action share between the whole team by each one's
1207/// count of bans, suspensions, warnings and document deletions since the
1208/// last settle, equally when nobody acted. Every part rounds down and the
1209/// remainder stays in the pot. The counts are `member id -> u32` items
1210/// without storage flags under key `48` of an elected contract's other tree,
1211/// created with the contract (`insert_contract_moderation_trees` v0), and
1212/// every settle deletes them. An `addedModerator` or `removedModerator`
1213/// created or deleted settles the pot first, to the team as it was, by a
1214/// hook in the batch's `validate_state` v0 beside the cap on additions: it
1215/// ignores the once-per-epoch limit and writes no last claim. The proof of a
1216/// claim by a seated team's member, whom the contract does not name as a
1217/// recipient, shows the claimant's balance alone. A moderation reason gains
1218/// `reasonDocumentId` (tag bit 2 where it is stored), and a seated team's
1219/// ban, suspension, warning or deletion must name a `reason` document its
1220/// proposal lists (`ModerationReasonNotListedError`, 41203). No table moves
1221/// but the four
1222/// new Drive method slots, `0` at every version. The counts are read with
1223/// the `getContractModerationActionCounts` query (an elected contract
1224/// only), whose proof reads the whole counts tree; it adds a fifth contract
1225/// method slot (`prove_contract_moderation_action_counts`), a verify slot
1226/// (`verify_contract_moderation_action_counts`) and the query's bounds
1227/// (`contract_moderation_action_counts`), `0` at every version as well.
1228///
1229/// 42. **Repaid identity debt reaches the processing fee pool**: an identity
1230/// whose fee the balance could not fully cover keeps the unpaid processing
1231/// part as a debt (its negative credit balance), and credits it receives
1232/// while its balance is empty still repay that debt first. The repaid part
1233/// now goes to the processing fee pool of the epoch it is repaid in, where
1234/// the unpaid fee would have gone; before, it reached no balance the credit
1235/// sum counts. `add_to_identity_balance` 1 marks it with a
1236/// `LowLevelDriveOperation::RepaidIdentityDebt`, and every apply routes it:
1237/// `apply_drive_operations` 1 writes it to the pool after the batch (so it
1238/// adds to the end of block fee distribution the same batch may write,
1239/// unbilled), `apply_balance_change_from_fee_to_identity` 1, which now takes
1240/// the block info, writes it in its own batch (the fee paid is unchanged),
1241/// and `add_epoch_pool_to_proposers_payout_operations` 1 hands the epoch
1242/// payouts to the block's `apply_drive_operations` instead of converting
1243/// them to a plain grove batch, skips a share whose `payToId` has no
1244/// balance and caps each share at what is left of its masternode's payout.
1245/// An apply that meets one it does not route fails (`CorruptedCodeExecution`)
1246/// instead of dropping it. `apply_drive_operations` 1 also merges every
1247/// credit and debit one batch makes to an identity's balance into one net
1248/// write: each converts against the balance committed before the batch, so
1249/// a second write replaced the first and two credits to an indebted
1250/// identity repaid its debt twice.
1251///
1252/// 43. **The end-date cleanup of ended contested vote polls**: a block ends at
1253/// most `maximum_vote_polls_to_process` vote polls, the earliest end date
1254/// first, and removes their entries from the end-date queries.
1255/// `remove_contested_resource_vote_poll_end_date_query_operations` 2
1256/// (`DRIVE_VOTE_METHOD_VERSIONS_V3`) removes an end date only once none of
1257/// its vote polls remain: it reads the entries under the date and keeps the
1258/// date while any of them is not removed in the same batch, so the polls
1259/// left end in a later block.
1260///
1261/// 44. **The total supply ceiling bounds every mint and direct purchase**: a
1262/// token's total supply is stored in a sum item, so it can never pass
1263/// `i64::MAX`. Token mint and token direct purchase state validation 1
1264/// treat `i64::MAX` as the max supply when the token configures none (and
1265/// cap a configured one there), refusing a mint or purchase past it with
1266/// `TokenMintPastMaxSupplyError`, as a paid consensus error. State
1267/// validation 0 checked only a configured max supply, so such a transition
1268/// failed in execution as an internal error instead. Both now read the
1269/// total supply on every mint and purchase, and pay for that read.
1270///
1271/// 45. **A masternode vote towards an identity names a contender**: a
1272/// `ResourceVoteChoice::TowardsIdentity` vote for an identity that is not a
1273/// contender of the poll is refused, unpaid, with
1274/// `VoteChoiceNotAllowedForVotePollError` (40307) by `validate_state` 1 of
1275/// the masternode vote, which reads the contender's document reference
1276/// under the poll. The reserved keys of the poll's stored info, abstain
1277/// tree and lock tree are refused before that read. Before, a vote for an
1278/// unknown identity failed with an internal error, and a vote towards a
1279/// reserved key was counted as Lock or Abstain. `check_for_ended_vote_polls`
1280/// 1 also ignores the lock tally of a contest resolved without locking. No
1281/// table moves: both generations are selected by this version alone.
1282///
1283/// 46. **A raw state transition is exactly one encoded transition**:
1284/// `decode_raw_state_transitions` 1 (`DRIVE_ABCI_METHOD_VERSIONS_V10`)
1285/// decodes with `StateTransition::deserialize_from_bytes_untrusted_exact_in_version`,
1286/// so bytes left over after the transition are an invalid encoding
1287/// (`SerializedObjectParsingError`, 10002), refused unpaid in `check_tx` and
1288/// in block processing. Version 0 ignored them, so the transition with
1289/// anything appended executed as the original under another transaction
1290/// hash. Version 1 also reports a transition whose version is outside its
1291/// active range as `StateTransitionNotActiveError` (10603) instead of a
1292/// decode failure, naming whichever boundary of that range was missed: its
1293/// start for a version not active yet, its end for one already superseded.
1294///
1295/// 47. **A storage refund is clawed back from the epochs it was priced for**:
1296/// removing data in epoch E refunds its owner the shares of epochs E+1
1297/// onward, and the refund waits for the next epoch change to be taken out of
1298/// the epoch storage pools. `add_distribute_storage_fee_to_epochs_operations`
1299/// 1 (`DRIVE_ABCI_METHOD_VERSIONS_V10`) restores and subtracts it from the
1300/// epoch after the previous block's epoch, the one every pending refund was
1301/// priced in, so each of those epochs gives back its own share. The shares
1302/// of epochs that closed before the current one, skipped by a halt, and the
1303/// rounding leftovers come out of the current epoch. Version 0 started from
1304/// the epoch after the current one, so the current epoch kept most of its
1305/// refunded share and the later epochs gave back more than theirs. The
1306/// total taken out equals the refund in both.
1307///
1308/// 48. **An evonode's token claim covers only the epochs it read**: an
1309/// `EvonodesByParticipation` perpetual distribution weighs each cycle by the
1310/// claimant's share of the blocks proposed in the epochs it spans, from their
1311/// finalized epoch infos. Up to v13 the claim read at most
1312/// `drive_abci.query.max_returned_elements` (100) of them but evaluated its
1313/// whole range, up to 128 cycles (32,767 for a fixed amount), from the last
1314/// paid moment or, on a first claim, from the start of the distribution. An
1315/// evonode more than 100 epochs behind (about 2.5 years on mainnet, 4 days on
1316/// testnet) had every claim of a function other than a fixed amount fail as an
1317/// internal error, with its last paid moment never advancing, while a fixed
1318/// amount applied the share of the epochs read to the whole range. A claim
1319/// reaching an epoch whose info the fee distribution of the block had not
1320/// written yet (the previous epoch, in the first block of an epoch) failed or
1321/// was weighed the same way. `evonode_participation_rewards` 1
1322/// (`DRIVE_TOKEN_METHOD_VERSIONS_V2`) reads the epochs after the cycle start of
1323/// the last paid moment, at most `SYSTEM_LIMITS_V4.max_evonode_reward_claim_epochs`
1324/// (100, backfilled into the earlier tables) or one whole cycle when a cycle is
1325/// longer, and pays through the last whole cycle it read, which the claim stores
1326/// as the last paid moment, so an evonode that is behind is paid over several
1327/// claims. An epoch without finalized info before the last one read, one in which
1328/// no block was produced, counts as an epoch without blocks, and a claim that
1329/// read no whole cycle is refused, paid, with `InvalidTokenClaimNoCurrentRewards`.
1330/// `get_finalized_epoch_infos` now takes its limit from the caller; every other
1331/// caller passes the query bound it read before.
1332///
1333/// 49. **Documents with a time to live**: the doctype-level `ttl` keyword (meta-schema v3,
1334/// document type parser generation 3) makes the platform delete each document of the
1335/// type `ttl` seconds after its `$createdAt`, at most
1336/// `max_document_expirations_per_block` (128, `SYSTEM_LIMITS_V4`) weighing at most
1337/// `max_document_expiration_weight_per_block` (1,024 in documents plus their index levels)
1338/// per block after the block's state transitions (`expire_documents` 0 in
1339/// `DRIVE_ABCI_METHOD_VERSIONS_V10`). The keyword requires `$createdAt`, is refused
1340/// with `documentsKeepHistory`, `indexOnly` and a contested index, is at least
1341/// `min_document_ttl_seconds` (one hour) and at most `max_document_ttl_seconds` (one
1342/// year) at registration, and is fixed on update (`validate_update` 1). References treat such a type as deletable. Its
1343/// documents are stored without storage flags, indexed in the documents expirations
1344/// tree under `Misc` (created by `create_initial_state_structure` 4 and
1345/// `transition_to_version_14`), and pay the `document_ttl` group of `FEE_VERSION3`: a
1346/// price per byte for the time they live (tiers up to seven days, then per 9.125 days),
1347/// paid out to the epochs they live in (at most one era) through the lifetime storage fee
1348/// pools under `Pools` (`add_distribute_block_fees_into_pools_operations` 1),
1349/// plus their deletion prepaid as processing (per index level and per document byte; a
1350/// change that grows a document prepays its added bytes). From its expiry on, a
1351/// document can no longer be replaced, transferred, bought, repriced or restored by a
1352/// moderator (`DocumentExpiredError`, 40140), judged from its own `$createdAt`; its
1353/// owner may still delete it where `canBeDeleted` allows. See
1354/// `book/src/data-model/document-ttl.md`.
1355///
1356/// 50. **A contest accepts at most 1,000 contenders, and its end reaches every
1357/// one**: document create state validation 2 (`DRIVE_ABCI_VALIDATION_VERSIONS_V10`)
1358/// refuses, paid, a document that would add a contender to a contest holding
1359/// `max_contenders_per_contest` (`SYSTEM_LIMITS_V4`, 1,000) already
1360/// (`DocumentContestMaximumContendersReachedError`, 40141).
1361/// `add_contested_indices_for_contract_operations` 1
1362/// (`DRIVE_DOCUMENT_METHOD_VERSIONS_V4`) writes the last index value of a
1363/// poll started from this version as a count tree, so the join reads the
1364/// count in one element fetch; a poll started before keeps its plain tree
1365/// and has its contenders counted by a keys query of at most 1,000.
1366/// `maximum_contenders_to_consider` rises from 100 to 10,000, so the tally
1367/// of an ended poll, and the cleanup built from it, cover every contender
1368/// of a poll within the cap, and up to 10,000 of one that grew past it
1369/// before this version. `check_for_ended_vote_polls` 1 compares every tied
1370/// contender; version 0 compared at most 100.
1371///
1372/// 51. **The fund a contender pays doubles for every 50 contenders a contest
1373/// holds past 250**: the fund to join a contest is its fund doubled once
1374/// the contest holds `contested_document_contenders_before_fund_doubling`
1375/// (`FEE_VERSION3`, 250) contenders and again for every
1376/// `contested_document_contenders_per_fund_doubling` (50) more: 0.1 DASH
1377/// for the first 250 DPNS contenders, 0.2 for the next 50, up to 3,276.8
1378/// for the 951st to the 1,000th, so filling a contest costs 327,695 DASH
1379/// where it cost 100. A contender's prefunded voting balance is the most it
1380/// pays: document create state validation 2 refuses, paid, one stating less
1381/// than the fund to join (`DocumentContestNotPaidForError`, carrying that
1382/// fund), the first contender of a new contest included, and charges one
1383/// stating more only the fund to join, the rest staying with it. Document
1384/// create structure validation 1 leaves the amount to state validation;
1385/// version 0 wants exactly the contest's fund.
1386///
1387/// 52. **Property constraints judge what is stored, and read `$defs`**: to
1388/// `present` and `absent` (item 39), an object none of whose members is
1389/// present (`{}`, or `{ "inner": {} }` around one) is absent, since a
1390/// stored document reads it back as no object at all. A create or replace
1391/// carrying `meta: {}` was judged with `meta` present, and a later
1392/// transfer, purchase or price update, judged on the stored document, with
1393/// it absent. The parser (generation 3) reads the schema of a property
1394/// given as a `$ref` to the contract's `$defs` from the definition, as the
1395/// core parse does, when it checks a rule's string constants and defaults
1396/// against the property's `enum` and an `encryptedFor` key id's bounds; it
1397/// refused every such contract with a decoding error before.
1398///
1399/// 53. **Properties the platform generates (`generatedFrom`)**: the property
1400/// keyword (meta-schema v3, `apply_generated_from` 0, `GeneratedFrom` on
1401/// `DocumentProperty`) names a built-in `function` and its `params`,
1402/// properties of the same document type, as
1403/// `{ "function": "sys.stringTransformations.homographSafeASCII", "params": ["label"] }`.
1404/// System functions are named under `sys.`, leaving other names to
1405/// functions a contract may bring later. The `sys.stringTransformations`
1406/// functions take one string and change ASCII characters only, keeping
1407/// every other character, without Unicode tables: `lowercase`,
1408/// `uppercase`, `capitalize`, `camelCase`, `snakeCase`, and
1409/// `homographSafeASCII`, which lowercases, then maps `o` to `0` and `i`
1410/// and `l` to `1`, DPNS's label normalization over ASCII. The parser
1411/// checks at registration and update that `params` holds as many
1412/// properties as the function takes, each another string property that
1413/// is not generated itself, that neither the property nor a param is
1414/// transient or inside a transient object, and that every param sits
1415/// inside every object holding the property; a changed declaration is an
1416/// incompatible schema change, and `validate_update` 1 refuses a property
1417/// an update adds over params that all already existed
1418/// (`DocumentTypeUpdateError`, 40212); meta-schema v3 refuses the keyword
1419/// beside `$ref`, whose definition would replace it.
1420/// `fill_generated_properties` (0) writes a declared property a document
1421/// leaves out, from its params, in the action transformers of document
1422/// create, replace and index-only delete, before the contest resolution
1423/// and every check read the data, in `Document::try_from_create_transition`
1424/// and `try_from_replace_transition`, and in
1425/// `index_only_transition_entry_path_query`, the builder the prover and
1426/// the verifier share, with which proofs are built and checked. The client
1427/// transition builders, the SDK's contest fund lookup and the JS and FFI
1428/// property-constraint pre-checks call `regenerate_generated_properties`
1429/// (same slot) instead, which replaces a value the document holds and
1430/// removes it when a param is absent, so a transition built from a
1431/// fetched and edited document carries the value of its new params and
1432/// its contest is detected from it.
1433/// `DataContract::validate_document_properties` 0 calls
1434/// `validate_generated_from_properties` (`validate_generated_from` 0)
1435/// after the schema and `maxBytes`, and refuses a supplied value that is
1436/// not what the function generates, one without its params, or a document
1437/// repeating a key on the way to the property or a param, with
1438/// `DocumentPropertyNotGeneratedError` (10424). Every call site was
1439/// extended in place and is inert before this version, where the three
1440/// slots are `None` and the meta-schemas refuse the keyword.
1441///
1442/// 54. **An aggregate keyword names a top-level property**: `summable` and
1443/// `averageable` on an index, and `documentsSummable` and
1444/// `documentsAverageable` on a document type, name the integer property
1445/// each document adds to the sum. Drive reads its value from the top level
1446/// of the document, but the parser resolves the name among the flattened
1447/// properties and required fields, which also hold the dotted path of a
1448/// property nested in an object, and meta-schemas v1 and v2 bound only the
1449/// name's length. A contract naming `payment.amount` registered, and every
1450/// document create of the type then failed in Drive as an internal error.
1451/// Meta-schema v3 (`CONTRACT_VERSIONS_V6`) gives the four keywords the
1452/// property-name pattern `^[a-zA-Z0-9_]{1,64}$`, so a create or an update
1453/// carrying a dotted name is refused under full validation
1454/// (`JsonSchemaError`, 10101, paid in a block; `check_tx` does not fully
1455/// validate a contract). A contract stored with one still loads, since a
1456/// stored contract is parsed without full validation, but can no longer be
1457/// updated; no contract on mainnet or testnet names one.
1458/// 55. **A preallocated index's agreement source fits a tree key**: contract
1459/// create and update state validation 1 refuse, paid, a
1460/// `propertyAgreement` pair through which a preallocated index is keyed
1461/// when its referenced property can hold a value over 255 bytes
1462/// (`ReferencedDocumentPropertyAgreementInvalidError`, 40126): creating a
1463/// referenced document writes that value as a tree key, which failed with
1464/// an internal error for a value over 255 bytes, and for any value once
1465/// the property's midway size, which sized the estimate, passed 255
1466/// bytes. `add_document_for_contract_operations` 1 now estimates that
1467/// layer from the referring property, as an entry insert does, and
1468/// preallocates nothing for a referenced value wider than the referring
1469/// property can hold, which no referring document can agree with.
1470///
1471/// 56. **A `propertyAgreement` pair compares values, not index keys**:
1472/// document reference validation 0 judges each pair as two single values
1473/// (`Value::same_scalar_data`): strings as text, byte arrays and
1474/// identifiers as bytes, integers as numbers at any width, floats by
1475/// their `f64` bits (an integer against a float read as the float it
1476/// converts to, as a `number` carried as an integer is stored), booleans
1477/// as booleans. An identifier or byte array carried as an array of
1478/// `U8`s is the bytes it lists, as before; any other array agrees with
1479/// nothing. It compared the two sides' index key encodings, under which
1480/// `""` agreed with `"\0"`, and two equal values over 255 bytes, which
1481/// an unindexed string of 64 characters or more can hold, were refused
1482/// (`ReferencedDocumentPropertyMismatchError`, 40127).
1483///
1484/// 57. **Moderator abilities, and fields only moderators write**: the two
1485/// doctype keywords of moderator deletion (19) become one object,
1486/// `moderatorAbilities` (meta-schema v3): `delete` for
1487/// `canBeDeletedByModerators`, `deleteWithin` for
1488/// `canBeDeletedByModeratorsFor`, and `changeFields`, the top-level
1489/// properties only the contract's moderators write. The whole object is
1490/// fixed with the type (40212). `deleteKeepsRecord` (default true) says
1491/// whether a moderator's deletion leaves its removal record: without one the
1492/// type has no records tree, the query refuses it, a restore is refused
1493/// (41119) and the deletion is proved by the document's absence, which the
1494/// verifier learns from the contract. `deleteRefundsOwner` (default false)
1495/// says whether the owner is refunded its storage instead of forfeiting it
1496/// (the batch then carries no `ForfeitStorageRefunds`). `deleteKeepsFields`
1497/// lists property paths at any depth, and the timestamps and block heights
1498/// the type requires, whose values the removal record keeps, copied from
1499/// the document as it was deleted: what stays public once it is gone. It
1500/// needs a record, and is fixed with the type. A record keeping any
1501/// carries them behind bit 1 of its tag byte, encoded as the document
1502/// encodes its properties (a presence byte and the value per kept path,
1503/// the paths themselves not written) and read under the document's type,
1504/// and a record keeping none is written as before; the removals
1505/// response carries the bytes as `kept_fields` (field 8), and a
1506/// `moderatedDocument` reference's `where` pair on a kept property is
1507/// checked against the record's value. A property `changeFields` lists must be declared,
1508/// optional, stored, not immutable, neither a reference nor read by one,
1509/// neither generated nor a generation parameter, and in no contested index,
1510/// on a type that is not indexOnly; a type listing any keeps `$revision` even
1511/// when `documentsMutable` is false, and a lookup key or a list element's
1512/// list may not read such a field of the type it refers to.
1513/// `ContractUserModeration` gains the `ChangeDocumentFields` action: a
1514/// moderator (for a seated team, holding the new `changeDocumentFields`
1515/// ability, appended to `ModerationAbility`, on the type, and citing a
1516/// listed reason) sets or removes those fields on any document of the type,
1517/// whoever owns it. The changed document is judged as a replace judges one
1518/// (schema, `propertyConstraints` with their totals, `distinctFrom`,
1519/// `encryptedFor` shapes, unique indexes through
1520/// `validate_moderated_document_uniqueness`, the restore's check
1521/// generalized and renamed), its references are not checked again, and it
1522/// is stored with the replace's update, `$revision` one higher and
1523/// `$updatedAt` untouched; the moderator pays, refunds of what the change
1524/// frees stay the owner's. A change that changes nothing is refused (10905),
1525/// and a seated team's change does not count toward its action share. An
1526/// elected declaration must give its team `changeDocumentFields` on every
1527/// type that lists fields. The proof
1528/// is the document as it now stands. The batch transformer (in place,
1529/// inert before 14) refuses a document's owner who sets, changes or removes
1530/// such a field without moderating the contract, in the mempool too. New errors:
1531/// `InvalidContractModerationDocumentFieldsError` (10905),
1532/// `DocumentFieldNotChangeableByModeratorsError` (41123) and
1533/// `DocumentModeratorFieldNotWritableError` (41124), appended.
1534/// 58. **The last moderator's stamp (`$moderatedAt`, `$moderatedBy`)**: two
1535/// system properties of a document whose type keeps fields for its
1536/// moderators (57), the block time and the identity of the last moderator
1537/// to write them. A `changeDocumentFields` sets both, and so does the batch
1538/// transformer (in place, inert before 14) for a create or replace whose
1539/// signer moderates the contract and writes such a field; a replace that
1540/// leaves the fields alone carries them over, and transfers, purchases,
1541/// price updates and restores keep them. Document serialization format 3
1542/// (this version's) records them behind bits 512 and 1024 of its time
1543/// field flags, so a document without them is written as before. Parser
1544/// generation 3 lets an index name either on such a type, never in a
1545/// unique index (10231); the shipped index key, query value and size
1546/// arms for the two names (`get_raw_for_document_type` v0,
1547/// `serialize_value_for_key` v0, Drive's estimated key sizes) are reached
1548/// only through such an index.
1549///
1550/// 59. **`skipIfAbsent` at any position, `true` or an array, on every type**:
1551/// document meta-schema v3 and the generation-3 parser take
1552/// `skipIfAbsent: true` (skip on every optional property of the index)
1553/// or an array naming the skip set, and a skip property may sit at any
1554/// position of the index, under a `timeRange` window too. A stored type
1555/// may declare it (the array may then leave some optional properties on
1556/// the null key), except on a contested index or next to
1557/// `nullSearchable: false`; on an indexOnly type the skip set is every
1558/// optional property of the index and each optional property needs a
1559/// skip index of its own, without a `timeRange`. No `rankedCountable`
1560/// `at` level may sit above a skip property; on a stored type a ranking
1561/// at a skip property may not share its level with an index keeping the
1562/// null layout for it, and a skip property that is a byte array needs
1563/// `minItems` of at least 1. The v2 insert and delete walkers write an index's
1564/// entry only for a document carrying its skip set and build a level
1565/// only when an entry of the document sits at or below it; update 1
1566/// moves a replaced document into or out of a skip index; every index
1567/// picker (server and verifier) admits a skip index only for a query
1568/// binding each skip property, on a stored type with a constraint no
1569/// missing value can meet. A contract valid before keeps its layout and
1570/// queries: it could only skip on an indexOnly index's first property,
1571/// where both rules agree.
1572///
1573/// 60. **Integer-range indexes**: an index can declare an `integerRange`
1574/// transform (`on`, `range`, `step`, optional `phase < step`) that
1575/// buckets a required user integer property of at most 64 bits into
1576/// windows starting at `phase + k * step`; a start below the lowest
1577/// value of the property's integer type is clamped to it, so every
1578/// value is in at least one window. It shares the time-range machinery:
1579/// the grid-qualified level key, the walkers' fan-out (the insert, delete
1580/// and update walkers read one `IndexBucketing`), the overlap cap
1581/// (`SystemLimits::max_time_range_overlap_factor`) and the resolution
1582/// provenance that keeps raw queries off a bucketed index. The v1
1583/// `getDocuments` handler resolves the new `IN_INTEGER_RANGE` operator,
1584/// a typed `IntegerRangeSelection` naming one window by its start, to a
1585/// window-start equality from the query alone. `unique: true` needs
1586/// non-overlapping windows; the uniqueness probe (v1) looks in the
1587/// candidate's window and lets a document change its value within its
1588/// own window. An indexOnly type cannot declare one (its entries would
1589/// collide across rows that share a window); neither kind of bucketed
1590/// index can be a `refersTo` lookup target or a `propertyConstraints`
1591/// answering index; a nested source must sit in required objects and
1592/// the grid-qualified level key fits 255 bytes; and a document `ttl`
1593/// prices every window an integer-range index writes.
1594///
1595/// 61. **A `refersTo` may find its document by a hash the document reveals**:
1596/// a `findBy` entry may be a function, `"<referenced property>": {
1597/// "function": "sys.hash.sha256d", "params": [...] }` (meta-schema v3
1598/// `findByFunction`, parser generation 3, `apply_property_reference` 0):
1599/// the document is found by that property holding the SHA-256 of the
1600/// SHA-256 of the params' bytes joined in order, a property path of the
1601/// document (the property carrying the reference included),
1602/// `{ "const": text }`, or `"."` for a value without a path (each element
1603/// of a typed array, the writer, the creator), a string counting as its
1604/// UTF-8, a byte array as its bytes, an identifier as its 32 bytes. The
1605/// parser holds the function as the lookup's computed key
1606/// (`LookupKeySource::Hash`). The function is `SystemFunction::Hash`, a
1607/// `sys.hash` namespace beside the string transformations of
1608/// `generatedFrom`, which refuses it. A string or byte array property may
1609/// now carry a `refersTo` whose function reads its value
1610/// (`DocumentProperty::revealed_reference`, `PropertyReference::Revealed`);
1611/// the property keeps its type. The document such a key finds is a
1612/// commitment made earlier, so the reference is judged when the document is
1613/// created only: its params may be transient or optional, every stored value
1614/// it reads must be fixed once written, and a replace leaves it alone.
1615/// Document create structure validation 1 refuses a create missing a param,
1616/// repeating a key on the way to one, or whose variable-length param holds
1617/// the one-byte separator that must follow it
1618/// (`DocumentReferencePreimageInvalidError`, 10423). Beside a `findBy`
1619/// function the reference may declare `minimumAgeBlocks`, judged by
1620/// document create state validation 2 against the found document's
1621/// `$createdAtBlockHeight` (`ReferencedDocumentRequirementNotMetError`,
1622/// 40142), and `consume`, which deletes the found document with the create
1623/// (`DocumentCreateTransitionAction` `consumed_documents`, a batch touching
1624/// it elsewhere refused with 40120). The hash is computed once per key and
1625/// billed as `ValidationOperation::DoubleSha256` by the blocks it hashes,
1626/// beside the document fetch. Such a `deletableDocument` reference, judged
1627/// on the create alone, may sit on an `immutable` property, which
1628/// `validate_no_immutable_deletable_element_references` otherwise refuses.
1629/// A `where` entry `{"$ownerId": "$ownerId"}` makes the commitment the
1630/// writer's own, and `consume` requires it, into the declaring contract,
1631/// on a type whose owners may delete, that keeps no history, declares no
1632/// delete token cost or delete action fee and requires no stricter
1633/// signature security level than the declaring type; batch advanced
1634/// structure 1 refuses a contract-bound key whose bounds leave out a type
1635/// the created type may consume (`ContractBoundedKeyOutOfBoundsError`,
1636/// 20014). The consumed deletes are converted with the create's own
1637/// operations pending, so a type may consume its own documents. The
1638/// `where` entries beside a function are judged with it, on the create
1639/// alone, so the properties they read must be fixed once written or
1640/// transient; on a mutable type such a reference may not be an `anyOf`
1641/// operand; and no property a function reads may be listed under
1642/// `moderatorAbilities.changeFields` (57). `creatorRefersTo` takes a
1643/// `deletableDocument` target through a function, and the `findBy` of an
1644/// `ownerRefersTo` or `creatorRefersTo` may leave the value out beside
1645/// one. The declaration reproduces the DPNS preorder hash of a name under
1646/// a parent byte for byte; the DPNS contract and its create trigger are
1647/// unchanged. See `book/src/data-model/documents.md`.
1648///
1649/// 62. **Null flags follow each index's own path**: the v2 index-level
1650/// insert and delete walkers give each sub-level the null flags of its
1651/// parent and its own value. They carried the flags from one sibling
1652/// sub-level into the next, so a unique index could store its entry in
1653/// the `[0]` tree meant for a missing value, and a `nullSearchable:
1654/// false` index an entry for a document missing all of its values,
1655/// because of another index's values; update 1 and the document cost
1656/// model already judged each index alone. Entries written before
1657/// (by that carrying, or by update 0, which laid out a unique index
1658/// with some values missing as the bare reference and never skipped a
1659/// `nullSearchable: false` entry) are found where they are stored: where
1660/// an earlier writer could disagree with the rule, the v2 delete walker
1661/// and update 1 read the stored `[0]`, unbilled, and remove or refresh
1662/// the entry there; a type with a `ttl` skips the read.
1663///
1664/// 63. **`refersTo` finds its document with `findBy` and checks it with
1665/// `where`**: the reference keywords the notes above describe are spelled
1666/// anew in meta-schema v3 and parser generation 3 (`apply_property_reference`
1667/// 0), in place, before this version reaches a network. `lookup: { index,
1668/// keys }` is `findBy`, the key parts directly (`{ "<index property>":
1669/// <source> }`, a function entry included, see 61), without the index
1670/// name: the index is the unique one of the referenced document type whose
1671/// properties are exactly those `findBy` names, not bucketing its first
1672/// property (`DocumentReferenceLookup::resolve_index`, run at contract
1673/// parse or registration and when the document is fetched; a type's
1674/// indexes never change after it is registered). A plain `propertyAgreement`
1675/// pair `{ "<referring>": "<referenced>" }` is a `where` entry keyed the
1676/// other way, `{ "<referenced>": "<referring>" }`, so every map of a
1677/// `refersTo` is keyed by the referenced document's property; the parsed
1678/// model keeps `property_agreement` keyed by the referring property, and a
1679/// referring value may be compared once. `listElement` is a
1680/// `permanentDocument` with `inList`, found by `findBy { "$id":
1681/// "<property>" }`, the one `findBy` entry that names `$id`. Without
1682/// `findBy` the value is the document's `$id`, as before. The parser refuses
1683/// `lookup`, `propertyAgreement` and the `listElement` type on every parse,
1684/// naming what replaced each, so a contract written with them never loads
1685/// with another meaning. `ReferencedDocumentLookupInvalidError` (40137)
1686/// carries the properties `findBy` names in place of an index name. The
1687/// moderation charters system contract is written in the new keywords;
1688/// the parsed declarations, and so validation and execution, are
1689/// unchanged.
1690/// 64. **`refersTo: moderatedDocument`**: a third kind of document reference,
1691/// between `permanentDocument` and `deletableDocument` and disjoint from
1692/// both (`DocumentReferenceKind`, `DocumentTypeV2Getters::document_reference_kind`),
1693/// in place in meta-schema v3, parser generation 3 and the generation 0
1694/// reference validators. Its target is a document type whose documents
1695/// leave state only when the contract's moderators remove them, each
1696/// removal on the record: `canBeDeleted: false`, no `ttl`, and
1697/// `moderatorAbilities.delete` with `deleteKeepsRecord` not false. Such a
1698/// type is no longer a `deletableDocument` target
1699/// (`ReferencedDocumentTypeModeratedError`, 40144), and a
1700/// `moderatedDocument` reference to any other type is refused
1701/// (`ReferencedDocumentTypeNotModeratedError`, 40143), at registration
1702/// and at write time. The id form only: no `findBy`, `inList` or operand
1703/// of an expression. The document must exist when the reference is
1704/// written; a replace re-validates it as a permanent one (the value or a
1705/// property its `where` reads changed, or always for a writer gate), and a
1706/// value the stored document held whose document a moderator removed
1707/// resolves to the removal record, read and billed: a `where` pair asked
1708/// about again compares the record's document owner for `$ownerId` and the
1709/// id for `$id`, and refuses any other property
1710/// (`ReferencedDocumentRemovedError`, 40145); a writer gate may compare
1711/// only those two (parser, 10231), being asked about on every replace. A
1712/// value is held when it is the stored document's at its path, compared
1713/// through the stored values the replace action carries for a changed
1714/// top-level property. The write-time kind check still lets a
1715/// `deletableDocument` reference to a moderated type through, which a
1716/// contract registered before this note may hold. Chained and composite joins
1717/// through it prove, as one more component of the merged proof, the
1718/// removal records of the joined ids beside their documents, and report
1719/// each removed document by its record (`removed_outer_documents = 4` on
1720/// `ChainedDocuments`, `removed = 4` on a composite `SubQueryResult`,
1721/// additive); a joined id with neither a document nor a record is refused
1722/// as a missing permanent target is. StateError discriminants 156-158.
1723///
1724/// 65. **An index may hold a value of the document a reference points at**: an
1725/// index property `"<reference property>.<field>"` (`DerivedIndexProperty`,
1726/// `DocumentTypeV2Getters::derived_index_properties`), such as a reply's
1727/// `postId.$ownerId`, in place in parser generation 3 (`admit_derived_index_properties`,
1728/// `apply_derived_index_properties`) and `create_document_types_from_document_schemas`
1729/// 1 (`resolve_derived_index_properties`, which gives a schema field its type on the
1730/// referenced type on every parse). The document never stores the value: before Drive
1731/// keys a document of such a type, on insert (`add_document` 1), update (`update_document`
1732/// 1, one read for both versions) and delete (`delete_read_document`, shared by owner and
1733/// moderator deletes and `ttl` expiry), it reads the referenced document, billed with the
1734/// write, or, for a `moderatedDocument` target a moderator removed, the owner and the
1735/// values its removal record keeps (`ContractDocumentRemoval::kept_values`, read at a
1736/// path by `kept_value_at`), and puts the values into the document's properties under
1737/// the derived names, where `get_raw_for_document_type` 0 reads them (a missing one is
1738/// refused, never keyed under null) and the serialization ignores them. A create reads nothing more: the
1739/// document reference validation 0, given a map, records the values from the documents it
1740/// fetched, and the create action carries them to Drive. A dry run keys the document
1741/// under a value of each field's type. `serialize_value_for_key` 0,
1742/// `deserialize_value_for_key` 0 and Drive's estimated key sizes take a derived name's type
1743/// from the declaration. Registration (full validation, `InvalidContractStructure`)
1744/// admits one only where the value can not change once written: a same-contract
1745/// `permanentDocument` or `moderatedDocument` reference by id, on a reference property
1746/// fixed once written; `$ownerId` of a type that can not change hands, `$creatorId` of a
1747/// type recording it, or a stored schema property fixed once written and indexable;
1748/// through `moderatedDocument`, `$ownerId` or a schema property the referenced type keeps
1749/// under `moderatorAbilities.deleteKeepsFields` (a kept path or one inside a kept object,
1750/// `is_path_listed`, checked in every build); not `$id`; not in a unique or contested
1751/// index, or as a `timeRange` or `integerRange` source; not on an indexOnly type. A
1752/// `skipIfAbsent` array may name one (`reads_through_reference`), which `skipIfAbsent:
1753/// true` leaves out; `resolve_derived_index_properties` refuses one that is never absent
1754/// (a required reference reading `$ownerId`, `$creatorId`, or a field required with every
1755/// object around it) or a byte array that may be empty. The v2 walkers, update 1 and the
1756/// SDK cost walker count a null skip value as absent (`document_carries`), as a derived
1757/// value is when its reference or field is. A `startAt` or `startAfter` cursor, placed by
1758/// what the named document stores, is refused on an index whose derived properties the
1759/// query does not fix with `==`. Every step is inert without a derived index property,
1760/// which only generation 3 declares.
1761///
1762/// 66. **Properties frozen under a condition**: an `immutable` entry of
1763/// meta-schema v3 and parser generation 3, in place, may be
1764/// `{ "property", "when" }` beside a property name. The condition takes
1765/// the grammar of a `propertyConstraints` rule, reads no `countOf` or
1766/// `sumOf`, and is judged on the document the replace writes (its
1767/// `$updatedAt` the replace's block time, so `$updatedAt - $createdAt`
1768/// is the document's age), with the stored document's properties read
1769/// through `$old.<path>` (`STORED_DOCUMENT_PREFIX`), which only such a
1770/// condition may read. Document replace state validation 1, extended in
1771/// place, refuses a replace changing, adding or removing a property whose
1772/// condition holds, or faults, with `DocumentImmutablePropertyChangedError`
1773/// (40128); the stored properties are rebuilt from the written ones and
1774/// `stored_changed_values`, and the replace action's `added_data_fields`
1775/// is gone. `immutableAllowSetting`, which `{ "present": "$old.<p>" }`
1776/// now says, is refused on every parse, naming its replacement. A
1777/// conditional property is not fixed once written
1778/// (`schema_property_is_fixed_once_written`), a `deletableDocument`
1779/// reference by id may be listed only without a condition, and on
1780/// contract update (document type update validation 1) a condition is
1781/// kept as it is or dropped for listing the property without one.
1782///
1783/// 67. **A seated team deletes a settled document together**: past a type's
1784/// `deleteWithin` window no moderator deletes a document alone (41116); the
1785/// new `moderatorAbilities.deleteSettled: { leader, approvals,
1786/// approversPredateDocument }` (meta-schema
1787/// v3, `DocumentTypeV2::moderator_settled_deletion`, fixed with the type,
1788/// 40212) lets the members of an elected contract's seated team delete it
1789/// once `approvals` of them approve, the leader among them when `leader` is
1790/// set. It needs `deleteWithin` and an elected declaration giving the team
1791/// `deleteDocuments` on the type (10231, 10900), `approvals` from 1 to the
1792/// members the declared team can hold (its leader,
1793/// `SystemLimits::max_moderation_charter_elected_members` and the
1794/// declaration's `maxAddedModerators`), the upper bound checked at
1795/// registration only; a seated team whose charter elects fewer members,
1796/// and so holds fewer than the rule asks for, must have all it can hold
1797/// approve. Its `approversPredateDocument` (default `true` when `approvals`
1798/// is above 1, which then needs `$createdAt` in `required` at
1799/// registration, 10231) counts a member the leader added only for
1800/// documents created after its addition (the `addedModerator`'s
1801/// `$createdAt` earlier than the document's): a proposal or approval by a
1802/// later one is refused, checked before an approval already given, and an
1803/// approval that reads the team drops the approval of a member taken off
1804/// and added again too late; the leader and the elected members always
1805/// count.
1806/// `ContractUserModeration` gains two actions (appended), shaped like a
1807/// token group's action: `DeleteSettledDocument` proposes the deletion, kept
1808/// under the contract as a team action (other tree key `24`, `M` active and
1809/// `X` closed, each `action id -> { I: the action, S: SumTree(member ->
1810/// SumItem(1)) }`, created with the contract) by an id computed from the
1811/// contract, the proposer, its nonce, the document and the reason,
1812/// naming the document as it is (its last modification and `$revision`)
1813/// and the reason; and
1814/// `ApproveTeamAction { action_id }` approves it. Nothing lapses, but an
1815/// approval of a document changed since (its `$revision` moved, a
1816/// moderator's change of its fields included) is refused. Each approval is
1817/// its own sum item, never rewritten; when the approvals given could meet
1818/// the rule the team is read and the approvals of members who left are
1819/// dropped, refunded to them, and the one whose counted approvals meet it
1820/// deletes the document as `DeleteDocument` does, moves the action with the
1821/// approvals that counted to the closed actions (refunding each), and counts
1822/// toward the action share for every counted approver. The storage refund
1823/// forfeiture of a moderator's deletion now takes the document operations
1824/// alone (the document's bytes and any index subtree the deletion empties,
1825/// whoever paid for them), applied as a GroveDB batch of their own when the
1826/// batch also frees moderation storage someone is owed (a restored removal
1827/// record replaced, approvals moved or dropped), which is refunded as ever.
1828/// The proof is the signer's approval, active or closed
1829/// (`VerifiedContractTeamActionSignature`, appended); the new
1830/// `getContractTeamActions` (each action with its approval count, the sum
1831/// of its approvals tree) and `getContractTeamActionSigners` queries read
1832/// them. New errors, appended: `DocumentTypeNotDeletableOnceSettledError`
1833/// (41204), `ContractModerationTeamNotSeatedError` (41205),
1834/// `DocumentNotSettledError` (41206), `ContractTeamActionDoesNotExistError`
1835/// (41207), `ContractTeamActionAlreadySignedError` (41208),
1836/// `SettledDeletionNotRestorableError` (41209): a deletion the team approved
1837/// is never restored, by the leader or any member,
1838/// `ContractTeamActionAlreadyCompletedError` (41210),
1839/// `ContractTeamActionDocumentChangedError` (41211) and
1840/// `ContractTeamMemberAddedAfterDocumentError` (41212).
1841///
1842/// 68. **A preallocated index may be bound through `moderatedDocument`**:
1843/// `Index::preallocation_bindings`, in place, binds through a same-contract
1844/// `moderatedDocument` reference as through a `permanentDocument` one, and a
1845/// binding records its kind (`PreallocationBinding::kind`). Through a moderated
1846/// reference a binding holds only when the removal record of the referenced
1847/// document keeps every key it binds, the referenced `$id`, `$ownerId` or a property
1848/// the referenced type lists under `moderatorAbilities.deleteKeepsFields`
1849/// (`is_path_listed`), never `$creatorId`
1850/// (`PreallocationBinding::is_kept_on_removal`). `create_document_types_from_document_schemas`
1851/// 1 and `set_document_schema` refuse, under full validation, a preallocated index
1852/// with no binding that holds (`validate_preallocated_indexes_kept_on_removal`,
1853/// `InvalidContractStructure`); the reference validation 0 checks the key width of a
1854/// `where` pair only through a binding that holds; and the Drive insert of a referenced document
1855/// (`add_document_for_contract_operations` 1) and the document cost model
1856/// preallocate only through one that holds
1857/// (`Index::preallocation_bindings_for_target`, now given the referenced type).
1858/// A moderator's removal leaves the trees, like its record, and a restore,
1859/// which puts the document back through the create path, finds them in place.
1860/// Inert for every contract that could be registered before: a moderated
1861/// reference never bound a preallocated index.
1862///
1863/// 69. **Index entries that outlive a delete (`outlivesDelete`)**: an index
1864/// keyword of meta-schema v3 and parser generation 3, in place
1865/// (`Index::outlives_delete`, `IndexLevelTypeInfo::outlives_delete`,
1866/// `IndexLevel::outlives_delete_at_or_below`), admitted only on a
1867/// `timeRange` index with a `ttl` of an indexOnly type, without a sum and
1868/// on a type without `entryPayload`; every schema property must also sit
1869/// in an index that neither skips nor outlives deletes, the proof index
1870/// may not outlive deletes (`index_only_proof_index`), and the flag is
1871/// fixed with the index (`find_first_outlives_delete_change`). A delete
1872/// leaves such an index's entries to expire with their window: document
1873/// index-only delete state validation 0 and Drive's row-integrity gate do
1874/// not probe it, and the delete walkers (top and index level 2) skip it
1875/// (`level_removes_entry`, with `IndexLevel::cleared_on_delete_at_or_below`). The row commitment leaves `$createdAt` out when
1876/// every index involving it outlives deletes
1877/// (`index_only_row_commits_created_at`, read off the index structure's
1878/// root, `IndexLevel::created_at_indexed_only_by_outliving`, and shared by
1879/// the commitment, the delete transition's construction, advanced
1880/// structure validation 0, which then refuses a carried `$createdAt`, and
1881/// Drive's indexOnly delete, which refuses one too). Document create state
1882/// validation 1 and the within-batch collision tracker do not probe such
1883/// an index, and the indexOnly terminal insert writes over an entry
1884/// already standing there, without reading it. Registration requires the
1885/// index's key (its properties but `$createdAt`, and its terminal) to hold
1886/// the key of an index a delete clears that skips nothing, so no two
1887/// documents in state share one of its entries. Inert for every contract
1888/// without the keyword, which every earlier grammar refuses.
1889/// 70. **A contested type sums only small values**: parser generation 3, in
1890/// place, refuses under full validation a document type with a contested
1891/// index and a summed property (`summable`, `averageable`,
1892/// `documentsSummable` or `documentsAverageable`) unless the property's
1893/// schema declares a `minimum` of at least -2^27 and a `maximum` of at most
1894/// 2^27 (`SYSTEM_LIMITS_V4.max_contested_summed_value_magnitude`, `None` in
1895/// the earlier tables). The end of a contest writes the winner's document
1896/// into the type's sums with no transition to refuse, so the values must be
1897/// small enough that the sums stay in `i64`, which they do short of 2^36
1898/// documents. A stored contract still parses.
1899/// 71. **Documents deleted only when consumed (`canBeDeleted:
1900/// "onlyWhenConsumed"`)**: a third `canBeDeleted` value of meta-schema v3
1901/// and parser generation 3, in place
1902/// (`parse_can_be_deleted_only_when_consumed_keyword`, passed to the core
1903/// parse as `indexOnly` is, `false` for generations 1 and 2;
1904/// `DocumentTypeV2Getters::documents_deleted_only_when_consumed`). The
1905/// owner's delete reads it as `false` (document delete advanced structure
1906/// validation refuses it, 10404), and a `refersTo` with `consume` may
1907/// target the type (`DocumentReferenceLookup::referenced_side_error`,
1908/// which refused every type its owner can not delete). Its documents can
1909/// leave state, so the type is a `deletableDocument` target, never a
1910/// `permanentDocument` or `moderatedDocument` one
1911/// (`documents_can_disappear`, `document_reference_kind`). A consumed
1912/// document is deleted without its owner's `canBeDeleted` guard
1913/// (`ForceDeleteDocument` beside a contested create,
1914/// `force_delete_document_for_contract_operations` in
1915/// `AddDocumentAndDeleteConsumed`), so Drive's delete guard stays strict
1916/// for the owner's delete. Refused on a type that keeps history or is
1917/// indexOnly (10231), and fixed on update (`validate_update` v1, 40212).
1918/// Inert for every contract without the value, which every earlier grammar
1919/// refuses.
1920///
1921/// 72. **A barred author may still retract (`retractedWhen`)**: a document
1922/// type of meta-schema v3 and parser generation 3, in place, may declare
1923/// `retractedWhen`, one condition in the grammar of an `immutable` entry's
1924/// `when` (`$old.` reads, no `countOf` or `sumOf`), only on a mutable type
1925/// of a contract keeping a banlist or a suspension list (10231 on every
1926/// parse), and fixed on update (document type update validation 1, 40212).
1927/// `contract_moderation_gate` v0, in place, lets a banned or suspended
1928/// signer's replaces on such a type through with its bar
1929/// (`ContractModerationRefusal::retraction_bar`, `refused` now optional),
1930/// and the shared transformer, after fetching the stored document, refuses
1931/// with the bar (41107, 41108), paid with the nonce bumped, each whose
1932/// written document does not meet the condition or whose condition
1933/// faults. Every other rule of the type still judges the replace. So an
1934/// author whose documents can not be deleted can still take one back. Inert
1935/// before this version: the gate and the keyword exist only here.
1936///
1937/// 73. **An index that counts another index's entries
1938/// (`summableOffCountIndex`)**: an index keyword of meta-schema v3 and
1939/// parser generation 3, in place (`Index::summable_off_count_index`,
1940/// `IndexLevelTypeInfo::summable_off_count_index`), admitted only on an
1941/// indexOnly type with `rangeSummable`, naming a source index of the type
1942/// that holds every document once; its other properties must be fixed by
1943/// the source through unchanging `where` values of same-contract
1944/// `permanentDocument` or `moderatedDocument` references
1945/// (`validate_summable_off_count_indexes_lossless`, judging a value as a
1946/// lookup's key part is judged, `why_value_can_change`: an optional
1947/// `deletableDocument` reference by id a replace may clear once its
1948/// document is deleted is not fixed, and from this version neither is a
1949/// findBy key part, a findBy function's param or a `where` value beside
1950/// one), and one summed value per type is kept. Such an index keeps one `Element::SumItem` per group
1951/// in place of a value tree and entries: the index walkers (insert and
1952/// delete index level 2) move it by one per document, preallocation
1953/// creates it at zero, and document create state validation 1, document index-only delete
1954/// state validation 0, the within-batch collision tracker and the proof
1955/// index never use it. `rankedSummable` and `rankedAverageable` gain the
1956/// `{ "at": ... }` form on such an index only, stamped on the index
1957/// levels (`IndexLevel::ranked_sum_grouping`, `ranked_average_grouping`,
1958/// `sum_propagating`) and laid out by Drive as sum chains, count-and-sum
1959/// chains where an average ranking or `rangeCountable` adds counts
1960/// (`property_name_tree_type_and_ranked_axes_for_level`,
1961/// `ranked_chain_value_tree_type`); its `rankedCountable` is parsed into
1962/// that Sum ranking, since a document count there is its sums (no
1963/// `rangeCountable` needed). Sum, average and ranked queries name
1964/// the source index for the summed value, and a count query reads such
1965/// an index's sums, its document counts: a point read
1966/// (`document_count_of_element`), and a ranked or having-range read on
1967/// its Sum secondaries (`read_axis_for`), and a range read through the
1968/// sum surface's range forms (`counter_sums_query`). A range total
1969/// through any index whose path passes through a ranked level (its own,
1970/// or one another index ranks at a shared level) is refused cleanly
1971/// (`refuse_a_range_total_through_a_ranked_index`). Drive's batch methods,
1972/// `apply_drive_operations` and `convert_drive_operations_to_grove_operations`
1973/// at version 1, refuse a batch moving one document type's counters for
1974/// more than one document (`refuse_repeated_counter_moves`). Needs
1975/// grovedb's `GROVE_V4`, which admits a bare `SumItem` under a
1976/// `ProvableCountProvableSumIndexedTree`. Inert for every contract without
1977/// the keyword, which every earlier grammar refuses. For any index, the
1978/// range-total verifiers at version 1 (`DRIVE_VERIFY_METHOD_VERSIONS_V3`:
1979/// `verify_aggregate_count_proof`, `verify_carrier_aggregate_count_proof`,
1980/// `verify_aggregate_sum_proof`, `verify_carrier_aggregate_sum_proof`,
1981/// `verify_aggregate_count_and_sum_proof` and
1982/// `verify_carrier_aggregate_count_and_sum_proof`) verify a proof showing
1983/// the range holds nothing (an equality value no document holds, or an
1984/// empty tree of a kind the read does not aggregate), which grovedb's
1985/// aggregate verifiers refuse, as a zero total or no carrier branch
1986/// (`or_empty_range_total`), and the unproven range totals, keyed on the
1987/// same verifier versions, read an absent value as zero
1988/// (`aggregate_or_zero_when_absent`); and
1989/// `verify_composite_documents_proof` 1 reads the sum-bearing items of a
1990/// `documentsSummable` type as documents. Their
1991/// version 0, which every earlier protocol version selects, refuses both
1992/// proofs, and the unproven total fails, as released; the prover is
1993/// unchanged.
1994///
1995/// 74. **Withdrawals also fit a Core-anchored limit**: pooling
1996/// (`pool_withdrawals_into_transactions_queue` 2, which reuses version 1's
1997/// pooling through a shared helper) admits withdrawals up to the smaller of
1998/// the daily withdrawal limit (note 4) and
1999/// `calculate_core_anchored_withdrawal_limit`, a stricter copy of Core v24's
2000/// relative net unlock rule (dash#7712) read from Core's own credit pool
2001/// balances at chain locked heights: the pool may drop by at most
2002/// `core_credit_pool_unlock_limit_percent` (15; Core allows 20) of its
2003/// highest balance at a window start Core may use for the unlock (Core's
2004/// window, `core_credit_pool_window_blocks` 576 or
2005/// `regtest_core_credit_pool_window_blocks` 100, back from the chain locked
2006/// height, up to Core's asset unlock validity, `core_expiration_blocks` 48,
2007/// later), at least
2008/// `core_credit_pool_unlock_limit_floor` (1500 Dash; Core's floor is 2000),
2009/// less what is queued or broadcast and not completed yet. The formula is
2010/// `core_credit_pool_unlock_limit` 0 in `DPP_METHOD_VERSIONS_V3`. Before
2011/// pooling, `scan_core_blocks_for_withdrawals` reads the Core blocks the
2012/// chain locked height passed (at most `core_blocks_scanned_per_block_limit`,
2013/// 32, per block) and records each one's credit pool balance, read from the
2014/// block's coinbase alone (`getspecialtxes`), under the withdrawals tree. The
2015/// Platform-side accounting can grant more than Core will mine (an asset lock published to
2016/// Platform after Core mined it, a whole epoch of Core rewards minted in one
2017/// block); over Core's limit an unlock waits unmined and is re-signed, and
2018/// while Core's mempool holds more than the limit Core InstantSend-locks no
2019/// withdrawal at all. The balance tree is created at genesis and by
2020/// `transition_to_version_14`, and `cleanup_expired_locks_of_withdrawal_amounts`
2021/// 1 prunes it by Core height.
2022///
2023/// 75. **No reference by id to an indexOnly document type**: the contract
2024/// reference validation 0 (`validate_data_contract_references`), in place,
2025/// refuses a `permanentDocument`, `deletableDocument` or
2026/// `moderatedDocument` reference without `findBy` (or with `inList`) whose
2027/// referenced document type, in the declaring contract or another, is
2028/// indexOnly (`ReferencedDocumentTypeIndexOnlyError`, 40146, StateError
2029/// discriminant 171). Such a type's documents exist only as index entries,
2030/// and Drive refuses to fetch one by id, so every write resolving the
2031/// reference failed with an internal error, dropped unpaid. A `findBy`
2032/// into one keeps its own refusal (40137, or 10231 in the declaring
2033/// contract). Inert before this version: only parser generation 3 admits
2034/// an indexOnly document type.
2035///
2036/// 76. **Every revealed nullifier is recorded once**: each action of an
2037/// outputs-only Orchard bundle reveals a nullifier (that of a dummy spend,
2038/// which becomes the new note's `rho`). The spends already recorded and
2039/// checked theirs; now `Shield`, `ShieldFromAssetLock` and
2040/// `ShieldFromIdentity` do too. `transform_into_action` 1 of the shield and
2041/// the shield from asset lock (`DRIVE_ABCI_VALIDATION_VERSIONS_V10`), and
2042/// `transform_into_action` 0 of the shield from identity in place, refuse a
2043/// nullifier repeated inside the bundle or already recorded, with
2044/// `NullifierAlreadySpentError`: unpaid for the first two, as for the
2045/// spends, and a paid nonce bump for the identity-signed one. The
2046/// high-level operations of the shield and the shield from asset lock 1
2047/// (`DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V4`), and of the shield from
2048/// identity 0 in place, record the nullifiers. Recording them is metered
2049/// storage for the shield and the shield from identity; the shield from
2050/// asset lock's flat pool fee already prices a note and a nullifier write
2051/// per action. The shield from identity's admission floor
2052/// (`compute_shielded_identity_balance_write_fee` 0, the client's estimate
2053/// of its complete fee) uses versioned allowances of 400 effective bytes
2054/// per action and 500 flat bytes, covering the complete execution-event
2055/// admission estimate. Actual fees remain metered. Nullifiers revealed by
2056/// shields before this version are not added.
2057///
2058/// 77. **Owner identities for shared and extended-address masternodes**: from
2059/// v24 on, Dash Core lists shared masternodes, which have no owner, payout
2060/// or collateral address, and extended-address masternodes, which have a
2061/// `payouts` list instead of a `payoutAddress`. `create_owner_identity` 1
2062/// needs both addresses and fails on such a masternode with
2063/// `DashCoreBadResponseError`, which fails the block. With
2064/// `create_owner_identity` 2 and `update_masternode_identities` 1
2065/// (`DRIVE_ABCI_METHOD_VERSIONS_V10`), a masternode without an owner
2066/// address gets no owner identity, only its voter and operator identities;
2067/// one with an owner address and either a legacy payout address or a sole
2068/// payout with a matching P2PKH script gets the version 1 identity,
2069/// TRANSFER key id 0 and OWNER key id 1, byte for byte; other payout shapes
2070/// get only OWNER key id 1. Legacy payout-address rotation is unchanged.
2071/// Payout-list changes retain, re-enable or add the sole supported P2PKH
2072/// TRANSFER key and disable obsolete TRANSFER keys. Split, empty or
2073/// unsupported lists disable all TRANSFER authority while preserving OWNER
2074/// and balance. Historical updaters keep their payout-list policy. This
2075/// version must be active on a network before its Dash Core activates V24,
2076/// since earlier versions keep failing on these masternodes.
2077///
2078/// 78. **Versioned Core masternode address resolution**: `update_masternode_list` 1
2079/// resolves nested platform addresses first, then falls back to legacy ports,
2080/// before storing the masternode state. Earlier protocol versions keep their
2081/// flat-field interpretation. The stored layout and validator construction
2082/// remain unchanged: new validators read the resolved stored ports, and an
2083/// existing validator is refreshed on a ban, service or P2P-port change.
2084/// Each diff starts from the old persisted representation so transient address
2085/// data retained before activation cannot make a running node disagree with
2086/// a restarted one. Payout lists remain outside the persisted representation.
2087///
2088/// 80. **A BLS12_381 signature must verify**: `verify_identity_signed_signature`
2089/// 1 (`STATE_TRANSITION_METHOD_VERSIONS_V2`), the signature check that
2090/// identity-signature validation runs for every identity-signed
2091/// transition, refuses a signature by a BLS12_381 key that does not verify
2092/// (`InvalidStateTransitionSignatureError`, unpaid, as for ECDSA keys).
2093/// Generation 0 refused one only when the key or the signature could not be
2094/// read, and earlier versions replay through it. Identity-signature
2095/// validation v0, in place, passes the platform version to the check; the
2096/// tables of every earlier version select generation 0, the code it called
2097/// before.
2098///
2099/// 81. **Token shielded pools**: a token configuration in format version 1
2100/// (`TokenConfiguration::V1`, admitted by `CONTRACT_VERSIONS_V6`'s
2101/// `token_configuration_format` bounds) can set `hasShieldedPool`, which
2102/// gives the token its own Orchard pool under
2103/// `[Tokens, TOKEN_SHIELDED_POOLS_KEY, token_id]` laid out like the credit
2104/// pool. A pooled token must leave its freeze, unfreeze and destroy-frozen-
2105/// funds rules unassigned, since notes have no owner to freeze. Seven batch
2106/// token transitions (`TokenShield`, `TokenUnshield`,
2107/// `TokenShieldedTransfer`, `TokenMintToPool`, `TokenBurnFromPool`,
2108/// `TokenClaimToPool` and `TokenDirectPurchaseToPool`, validated through
2109/// `DRIVE_ABCI_VALIDATION_VERSIONS_V10` and gated by
2110/// `TOKEN_SHIELDED_POOL_INITIAL_PROTOCOL_VERSION`) move tokens between an
2111/// identity balance, the supply and the pool or inside it; the identity
2112/// signs and pays the fee in credits, and every bundle binds its pool into
2113/// the Orchard sighash, since all pools share the empty-tree anchor an
2114/// unbound bundle would verify against: a spend bundle binds the token id
2115/// and the batch owner (a burn binds the burner: the batch owner, or the
2116/// proposer of a group action), plus the recipient and amount where tokens
2117/// leave the pool; an outputs-only bundle (`TokenShield`,
2118/// `TokenMintToPool`, `TokenClaimToPool`, `TokenDirectPurchaseToPool`),
2119/// whose anchor is never checked against a pool, binds a per-kind tag,
2120/// the token id and the batch owner (for a group action mint, the
2121/// proposer).
2122/// A batch carrying any of these bundles, or a document whose token cost
2123/// is paid out of a pool, has to hold the compute fee the bundles will be
2124/// charged (`compute_shielded_verification_fee` per bundle-carrying
2125/// sub-transition): the batch minimum balance pre-check v1
2126/// (`identity_minimum_balance_pre_check`) reserves it on top of the flat
2127/// per-sub-transition minimum, which is orders of magnitude smaller. A
2128/// batch without a bundle is asked for the flat minimum, unchanged, and
2129/// one that asks the contract owner to pay its gas is asked for its
2130/// principal alone as in item 11, the compute fee being gas. The floor
2131/// refuses only what fee validation would refuse later, but it refuses it
2132/// before the Halo 2 work: `TokenClaimToPool`'s proof is skipped in check
2133/// tx, since its claimable amount is only known against state, so without
2134/// the floor a signer between the two numbers cleared the mempool with no
2135/// verification run and every validator then did the verification inside
2136/// block validation, only to refuse the batch unpaid, leaving the same
2137/// bytes replayable. The same holds for the bundle of a group action's
2138/// non-proposing signer, whose proof check tx also skips.
2139/// The pool balances are a term of the token conservation check
2140/// (`calculate_total_tokens_balance` v1 in `DRIVE_TOKEN_METHOD_VERSIONS_V2`).
2141/// `record_token_shielded_pool_anchors`
2142/// (`DRIVE_ABCI_METHOD_VERSIONS_V10`) records and prunes the anchors of the
2143/// pools a block touched. The pools root tree is inserted by
2144/// `transition_to_version_14` and by `create_initial_state_structure` v4;
2145/// the six shielded queries accept an optional `token_id` to target a token
2146/// pool.
2147///
2148/// 82. **An expiring type sums only values that keep its sums in range**:
2149/// parser generation 3, in place, refuses under full validation a document
2150/// type with a `ttl` and a summed property (`summable`, `averageable`,
2151/// `documentsSummable` or `documentsAverageable`) unless the property's
2152/// schema declares a `minimum` of at least 0, or a `minimum` of at least
2153/// -2^27 and a `maximum` of at most 2^27
2154/// (`SYSTEM_LIMITS_V4.max_expiring_signed_summed_value_magnitude`, `None` in
2155/// the earlier tables). The cleanup deletes expired documents at the end of
2156/// a block with no transition to refuse, and removing a negative value
2157/// raises the sums it was in; removing values that are never negative only
2158/// lowers them, and values within ±2^27 keep them in `i64` short of 2^36
2159/// documents. A stored contract still parses. No earlier version parses
2160/// `ttl`.
2161///
2162/// 83. **Unambiguous document properties**: `validate_document` generation 1 rejects
2163/// repeated text keys in nested maps, including maps inside arrays, before property
2164/// size, path and schema validation. Create, replace, indexOnly delete and moderator
2165/// field changes use the same check. Rejection uses ValueError (10103) through the
2166/// existing paid-invalid flow; generation 0 remains selected before this version.
2167///
2168/// 84. **Document token payments obey the issuer's movement policy**:
2169/// document-base state validation 2 supersedes 1
2170/// (`DRIVE_ABCI_VALIDATION_VERSIONS_V10`). A transparent transfer or burn
2171/// payment of a paused token is refused (`TokenIsPausedError`, 40711).
2172/// A transfer to a frozen document contract owner is refused
2173/// (`IdentityTokenAccountFrozenError`, 40702, naming that owner) only when
2174/// the token issuer's `allowTransferToFrozenBalance` is false; its default
2175/// is true, and external issuers are included. Reads are billed in order:
2176/// payer freeze, payer balance, pause, recipient info, then issuer metadata
2177/// only if frozen, and the issuer contract only when external. Owner
2178/// self-payments emit no transfer and retain only their payer checks.
2179/// Shielded payments retain their separate pool validation; native burn
2180/// policy and earlier protocol tables are unchanged.
2181///
2182/// 85. **Rules that gate the owner's delete (`deleteConstraints`), and `$id`
2183/// in a total's filter**: a document type of meta-schema v3 and parser
2184/// generation 3, in place, may declare `deleteConstraints`, named rules in
2185/// the `propertyConstraints` grammar (`parse_delete_constraints`,
2186/// `apply_delete_constraints_v0`, run by `apply_property_constraints` 0
2187/// on `parse_property_constraints`; `DocumentTypeV2Getters::delete_constraints`).
2188/// Document delete state validation 1 (`DRIVE_ABCI_VALIDATION_VERSIONS_V10`)
2189/// runs the checks of version 0, then reads the totals the rules read
2190/// (`read_delete_constraint_aggregates`, billed, each as it will be once
2191/// the document is gone) and judges every rule on the stored document
2192/// (`validate_delete_constraints`, versioned with
2193/// `validate_property_constraints`), refusing the first one broken with
2194/// `DocumentDeleteConstraintViolatedError` (state code 40147, discriminant
2195/// 172), paid. A `countOf` or `sumOf` filter may match by `"$id"`, the
2196/// document's own id (`AggregateBinding::Id`, an identifier key, in
2197/// `propertyConstraints` too: the shared batch transformer's aggregate read,
2198/// in place, passes the document's id), so a poll is deleted only while no
2199/// vote names it. Refused on a type with `canBeDeleted: false`,
2200/// `"onlyWhenConsumed"` or `indexOnly` (10231, every parse), held to the rule
2201/// limits apart from `propertyConstraints`, frozen on update (10246), and a
2202/// `refersTo` with `consume` may not target such a type
2203/// (`DocumentReferenceLookup::referenced_side_error`). Moderator deletes and
2204/// `ttl` expiries are not judged. Inert before this version: the earlier
2205/// meta-schemas refuse the keyword and the `$id` filter value, and their
2206/// tables select delete state validation 0.
2207///
2208/// 86. **Bounded schema depth check**: `validate_max_depth` 1
2209/// (`CONTRACT_VERSIONS_V6`) no longer walks a `$ref` whose target is a
2210/// scalar and never clears its visited set, so every ref target is
2211/// expanded at most once and the check is bounded in schema size. Before
2212/// this a crafted `$defs` chain with `$ref`s to scalars cleared the cycle
2213/// guard and made the check, run during contract registration in block
2214/// execution, exponential. Verdict, depth and size are unchanged for
2215/// schemas without a scalar `$ref` target; earlier versions replay
2216/// through generation 0.
2217///
2218/// 87. **Moderator document restores obey `propertyConstraints`**: moderation state
2219/// validation 0, in place, judges every rule of the restored type after uniqueness
2220/// and before constructing restoration operations. The retained document supplies
2221/// its original id, owner, properties, times and heights. The shared aggregate reader
2222/// adds it to the live totals as an insertion, with no contribution from its removal
2223/// record. A failing rule returns paid `DocumentPropertyConstraintViolatedError`
2224/// (10422) in a block, charging the moderator and consuming its nonce while leaving
2225/// the document absent and the removal record unrestored. Mempool admission refuses
2226/// it without persisting fees or a nonce change. Types without rules retain their fees.
2227/// Full property schema validation and `deleteConstraints` are not added to restore.
2228/// Earlier versions are unchanged: contract moderation is inactive before version 14.
2229///
2230/// The app-connect system contract (`SystemDataContract::AppConnect`, schema v1)
2231/// carries only the wallet's `loginKeyResponse`: a flat indexOnly entry keyed by
2232/// the app's ephemeral key hash and the responding identity, with the wallet's
2233/// ephemeral key and encrypted grant in `entryPayload`. Genesis registers it on
2234/// chains born at this version; `transition_to_version_14` inserts it on upgrade.
2235/// The Drive and trusted SDK caches serve it only from protocol version 14.
2236///
2237///
2238/// * `ShieldFromIdentity` (state transition type 21) activates:
2239/// `SHIELD_FROM_IDENTITY_INITIAL_PROTOCOL_VERSION = 14` gates it in
2240/// `is_allowed`, and `DRIVE_ABCI_VALIDATION_VERSIONS_V10` is the first
2241/// table whose `shield_from_identity_state_transition` row enables basic
2242/// structure, identity signature, and nonce validation. It moves credits
2243/// from an identity balance straight into the shielded pool: the funding
2244/// side is identity-signed like `IdentityCreditTransferToAddresses`, the
2245/// pool side is an outputs-only Orchard bundle like `Shield`, bound to the
2246/// funding identity (next item), and the fee is metered plus the shielded
2247/// compute fee, paid from the identity.
2248///
2249/// * The credit pool's outputs-only bundles bind `kind tag || owner` into their
2250/// Orchard sighash (`DPP_METHOD_VERSIONS_V3` sets `credit_pool_bundle_binding`
2251/// to `Some(0)`): `Shield` (`0x84`) the SHA-256 of its input addresses,
2252/// checked by `validate_shielded_proof` v1; `ShieldFromIdentity` (`0x85`) its
2253/// identity id; `ShieldFromAssetLock` (`0x86`) its asset lock identifier,
2254/// checked by the `transform_into_action` v1 that
2255/// `DRIVE_ABCI_VALIDATION_VERSIONS_V10` selects. A third party can no longer
2256/// wrap a proved bundle in a transition of their own. v13 keeps both checks
2257/// unbound. A sender rebuilding the same notes (Faerie Gold) is not stopped:
2258/// that needs the bundles' dummy nullifiers recorded and checked.
2259/// `ShieldFromAssetLock` also gains transition version 1
2260/// (`STATE_TRANSITION_SERIALIZATION_VERSIONS_V3`), the only version 14
2261/// admits: version 0 is refused at decode by `active_version_range`, before
2262/// any proof work, uncharged and with its asset lock left unspent, so one
2263/// still waiting when 14 activates is not burned by the bound check.
2264///
2265/// * `IdentityTopUpFromShieldedPool` (state transition type 22) activates at the
2266/// same gate (`IDENTITY_TOP_UP_FROM_SHIELDED_POOL_INITIAL_PROTOCOL_VERSION = 14`,
2267/// `DRIVE_ABCI_VALIDATION_VERSIONS_V10` row). It spends shielded notes like
2268/// `Unshield` and credits an EXISTING identity's balance instead of a platform
2269/// address: pool-paid flat fee (`compute_shielded_identity_top_up_fee`), no
2270/// platform signature, the target identity and gross amount bound into the
2271/// Orchard sighash, and no system-credit adjustment (pool and identity balances
2272/// are both conservation-equation terms).
2273///
2274/// The wire surface changes only additively: `GetDocumentsRequestV1`
2275/// already carries `selects` / `group_by` / `order_by` / `limit` /
2276/// `offset`; the ranked response is an additive `ResultData.ranked`
2277/// variant, whose `skipped` field is likewise additive; and the v1
2278/// where-clause operator enum gains `IN_TIME_RANGE = 11` and
2279/// `IN_INTEGER_RANGE = 12`, which pre-v14 servers reject as unknown
2280/// operators rather than misread (the v0 wire has neither).
2281/// Contract-bound authentication keys activate through contract-bounds validation v2,
2282/// identity-signature validation v1 and batch advanced-structure v1. Identity creation
2283/// validates key bounds (state v1) and identity-update state v1 retains the contract
2284/// lookup fees; Drive identity methods v2 index and refresh the bound keys. The same v1
2285/// contract-info methods also store the current-key alias of a contract-level encryption or
2286/// decryption key bound under `MultipleReferenceToLatest` in its purpose subtree, where the
2287/// current-key query reads it; v0 wrote it one level up, where its sibling reference could
2288/// not resolve, so registering such a key failed inside Drive on every earlier version.
2289/// Contract group bounds on authentication keys ride the same versions: contract-bounds
2290/// validation v2 admits them, batch transform v2 resolves the member contract's group
2291/// memberships into the action (only for a group-bound signing key) for advanced-structure v1 to judge, and shielded-proof validation v1 refuses them in identity creation from the
2292/// shielded pool, whose sighash preimage layout predates them.
2293/// A transition carrying such a key is inactive before this version (`active_version_range`),
2294/// so earlier protocol versions reject it without charging, as a binary that cannot decode it does.
2295/// Authentication keys may carry a budget and an expiry (the version 1 public key format, which
2296/// `StateTransition::active_version_range` admits from 14). Key structure validation v1
2297/// (`STATE_TRANSITION_METHOD_VERSIONS_V2`) and `validate_identity_public_keys_limits` decide
2298/// which keys may carry them; Drive identity methods v2 write the remaining budget when the key
2299/// is added; identity-signature validation v1 refuses a key whose budget is spent;
2300/// `validate_fees_of_event` v1 refuses an expired key and a spend the remaining budget does not
2301/// cover (only metered processing may overshoot); `execute_event` v1 deducts what was spent.
2302/// Shielded-proof validation v1 refuses a key that carries a budget or an expiry in identity
2303/// creation from the shielded pool, whose sighash preimage does not cover the limits.
2304/// `IdentityKeyLimitsUpdate` (state transition type 23, gated by
2305/// `IDENTITY_KEY_LIMITS_UPDATE_INITIAL_PROTOCOL_VERSION`) raises a key's total budget, and the
2306/// remaining budget with it, or moves its expiry later; it only ever loosens limits. Signed by a
2307/// MASTER key or by a CRITICAL key without limits (`DRIVE_ABCI_VALIDATION_VERSIONS_V10` turns
2308/// its gates on; Drive identity methods v2 rewrite the key and raise the remaining budget).
2309pub const PLATFORM_V14: PlatformVersion = PlatformVersion {
2310 protocol_version: PROTOCOL_VERSION_14,
2311 drive: DRIVE_VERSION_V9, // changed: drive document method versions v4 — v2 index walkers (shared-prefix aggregate indexes become insertable) + the detect_ranked_mode slot; contract method versions v4: the moderation list trees, the document removal record trees and the moderation method table; apply_drive_operations 1 (a moderator's document deletion refunds nobody for what its document operations remove unless its type sets `deleteRefundsOwner`, those operations applied as a GroveDB batch of their own when the batch also frees moderation storage someone is owed, a restored removal record replaced or team action approvals moved or dropped, which is refunded to whoever its flags name; every write of one identity balance, fee pot or prefunded specialized balance in a batch merged into one; a batch writing one token balance or supply twice refused; a batch moving one document type's summableOffCountIndex counters for more than one document refused; repaid identity debt credited to the processing fee pool); convert_drive_operations_to_grove_operations 1 (refuses that counter batch too, then converts as before); index uniqueness gains validate_moderated_document_uniqueness (a moderator's document restore or field change); vote method versions v3: the end-date cleanup of ended contested vote polls removes an end date only once none of its polls remain; token method versions v2: calculate_total_tokens_balance 1 (token shielded pool balances join token conservation) and evonode_participation_rewards 1 (an evonode's token claim covers only the epochs it read); add_contested_indices_for_contract_operations 1: a poll's last index value is a count tree
2312 drive_abci: DriveAbciVersion {
2313 structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V2, // changed: saved platform state structure 1 keeps masternodes and validator sets as one aux entry each
2314 methods: DRIVE_ABCI_METHOD_VERSIONS_V10, // changed: records the per-block total credits history for the daily withdrawal limit; record_token_shielded_pool_anchors records and prunes the anchors of the token pools a block touched; decode_raw_state_transitions, execute_event, validate_fees_of_event and add_distribute_storage_fee_to_epochs_operations each move to 1 — the table's own per-slot comments carry the full list
2315 validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V10, // changed: contested-index cross-check + refersTo document reference validation; the ContractUserModeration gates and the batch transformer's contract_moderation_gate; a contest accepts at most max_contenders_per_contest contenders and maximum_contenders_to_consider rises to 10,000; a contender's fund doubles past 250 contenders and for every 50 more; the three shielded-fee token pool transitions gain basic structure validation and document_base_transition_state_validation 2 admits a document token cost paid from a token pool and enforces pause and the issuer's frozen-recipient policy on transparent payments; the ShieldFromAssetLock transform_into_action 1 checks its bundle against the bound preimage
2316 withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V3, // changed: prune bound for the total credits history
2317 query: DRIVE_ABCI_QUERY_VERSIONS_V2, // changed: ranked + boolean-HAVING routing gate; the v1 handler also resolves IN_TIME_RANGE from committed block time
2318 checkpoints: DRIVE_ABCI_CHECKPOINT_PARAMETERS_V1,
2319 },
2320 dpp: DPPVersion {
2321 costs: DPP_COSTS_VERSIONS_V1,
2322 validation: DPP_VALIDATION_VERSIONS_V5, // changed: validate_config_update 2 admits the contract moderation declaration of config V2
2323 state_transition_serialization_versions: STATE_TRANSITION_SERIALIZATION_VERSIONS_V3, // changed: the indexOnly delete-by-values kind (documentIndexOnlyDelete) joins the wire; ShieldFromAssetLock moves to version 1 alone; the ContractUserModeration transition
2324 state_transition_conversion_versions: STATE_TRANSITION_CONVERSION_VERSIONS_V2,
2325 state_transition_method_versions: STATE_TRANSITION_METHOD_VERSIONS_V2, // changed: public keys in creation may carry a budget or an expiry; verify_identity_signed_signature 1: a BLS12_381 signature must verify
2326 state_transitions: STATE_TRANSITION_VERSIONS_V4,
2327 contract_versions: CONTRACT_VERSIONS_V6, // changed: token_configuration_format max_version 1 admits the shielded pool opt-in; v3 document meta-schema hosts the ranked, refersTo, requiredSince and timeRange keywords; validate_structure_interval v1 rejects a zero epoch interval; config max_version 2 (the contract moderation declaration) and validate_moderation_config; validate_document 1 rejects repeated nested text keys
2328 document_versions: DOCUMENT_VERSIONS_V4, // changed: document serialization format 3 — the contract version stamp that enables `requiredSince` properties
2329 identity_versions: IDENTITY_VERSIONS_V1,
2330 voting_versions: VOTING_VERSION_V2,
2331 token_versions: TOKEN_VERSIONS_V3, // changed: distribution_function_evaluate v1 — deterministic libm for token reward math; reward_distribution_max_cycle_moment v1: the epoch claim cap no longer wraps; distribution_function_cycle_epochs v1: evonode cycles weighted by the epochs they span
2332 asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1,
2333 methods: DPP_METHOD_VERSIONS_V3, // changed: daily_withdrawal_limit v2 — a percentage of the total credits a day ago; credit_pool_bundle_binding Some(0) — the credit pool's outputs-only bundles bind a kind tag and their owner
2334 factory_versions: DPP_FACTORY_VERSIONS_V1,
2335 },
2336 system_data_contracts: SYSTEM_DATA_CONTRACT_VERSIONS_V3, // changed: DashPay v2 adds profile payment address fields (DIP-33); withdrawals v2 admits the terminal FAILED status
2337 // The TTL ephemeral-bytes rate (270 credits/byte to processing) rides
2338 // the shared storage table; it is dead below v14 (the `ttl` grammar
2339 // does not parse), so no table fork is needed.
2340 fee_version: FEE_VERSION3, // changed: contested document contribution reduced to 0.1 DASH; masternode vote cost reduced to 0.00002 DASH; moderation election fund of 0.5 DASH; a contender's fund doubles past 250 contenders and for every 50 more; registration surcharge for once-per-identity token distributions
2341 system_limits: SYSTEM_LIMITS_V4, // changed: daily withdrawal limit becomes 15% of the total credits a day ago + time-range overlap-factor cap (24) + time-range TTL cap (1 week) and per-write drop cap (32); max_contract_moderators, max_contract_suspension_until, max_contract_moderation_reason_length, max_contract_warnings_per_identity, max_contract_moderation_reason_documents and contract_document_restore_window_ms (a week); max_contenders_per_contest (1,000)
2342 consensus: ConsensusVersions {
2343 tenderdash_consensus_version: 1,
2344 },
2345};
2346
2347#[cfg(test)]
2348mod tests {
2349 use super::*;
2350 use crate::version::v13::PLATFORM_V13;
2351
2352 #[test]
2353 fn should_change_only_the_contested_document_and_once_per_identity_fees_at_protocol_14() {
2354 for protocol_version in 1..14 {
2355 let version = PlatformVersion::get(protocol_version).expect("known protocol version");
2356 let fund_fees = &version.fee_version.vote_resolution_fund_fees;
2357 assert_eq!(
2358 fund_fees.contested_document_vote_resolution_fund_required_amount, 20_000_000_000,
2359 "protocol {protocol_version} must preserve the 0.2 DASH contribution"
2360 );
2361 assert_eq!(
2362 version
2363 .fee_version
2364 .vote_resolution_fund_fees
2365 .contested_document_single_vote_cost,
2366 10_000_000,
2367 "protocol {protocol_version} must preserve the 0.0001 DASH vote"
2368 );
2369 // No moderation election exists before 14; its amount is the contested one, so
2370 // a shipped path choosing between the two cannot change what it charges
2371 assert_eq!(
2372 fund_fees.moderation_vote_resolution_fund_required_amount,
2373 fund_fees.contested_document_vote_resolution_fund_required_amount,
2374 "protocol {protocol_version}"
2375 );
2376 assert_eq!(
2377 (
2378 fund_fees.contested_document_contenders_before_fund_doubling,
2379 fund_fees.contested_document_contenders_per_fund_doubling
2380 ),
2381 (0, 0),
2382 "protocol {protocol_version}: every contender paid the same fund"
2383 );
2384 }
2385
2386 let mut expected_fees = PLATFORM_V13.fee_version.clone();
2387 expected_fees
2388 .vote_resolution_fund_fees
2389 .contested_document_vote_resolution_fund_required_amount = 10_000_000_000;
2390 // A masternode vote costs a fifth of what it did: 0.00002 DASH from the contest's fund
2391 expected_fees
2392 .vote_resolution_fund_fees
2393 .contested_document_single_vote_cost = 2_000_000;
2394 // An application in a moderation election prefunds its masternode votes with 0.5 DASH
2395 expected_fees
2396 .vote_resolution_fund_fees
2397 .moderation_vote_resolution_fund_required_amount = 50_000_000_000;
2398 // The fund a contender pays doubles once the contest holds 250 contenders, and again for
2399 // every 50 more
2400 expected_fees
2401 .vote_resolution_fund_fees
2402 .contested_document_contenders_before_fund_doubling = 250;
2403 expected_fees
2404 .vote_resolution_fund_fees
2405 .contested_document_contenders_per_fund_doubling = 50;
2406 // The once-per-identity token distribution exists from protocol version 14 on, and a
2407 // token that uses it pays the surcharge of the other distribution kinds.
2408 assert_eq!(
2409 expected_fees
2410 .data_contract_registration
2411 .token_uses_once_per_identity_distribution_fee,
2412 0
2413 );
2414 expected_fees
2415 .data_contract_registration
2416 .token_uses_once_per_identity_distribution_fee = 10_000_000_000;
2417 assert_eq!(PLATFORM_V14.fee_version, expected_fees);
2418 }
2419
2420 /// The ranked / boolean-HAVING routing gate lives in v14's own query
2421 /// table, so flipping it touches only v14: a v13 node keeps running
2422 /// the v0 helper, which rejects every non-empty HAVING, so a
2423 /// mixed-version network agrees until the upgrade vote carries.
2424 ///
2425 /// v14 selects the v2 helper, which routes the ranked shape
2426 /// (`ORDER BY <agg> LIMIT n`) to `dispatch_ranked_v1` and the
2427 /// boolean-HAVING range shape (exactly one `having` clause on the
2428 /// selected aggregate) to `dispatch_having_v1`. A change that made
2429 /// v13 non-zero here would be consensus-breaking for
2430 /// already-deployed nodes, which is exactly what the v13 half of
2431 /// this assertion guards.
2432 #[test]
2433 fn ranked_having_routing_gate_is_v14_only() {
2434 assert_eq!(
2435 PLATFORM_V13
2436 .drive_abci
2437 .query
2438 .document_query_helpers
2439 .compute_aggregate_mode_and_check_limit,
2440 0
2441 );
2442 assert_eq!(
2443 PLATFORM_V14
2444 .drive_abci
2445 .query
2446 .document_query_helpers
2447 .compute_aggregate_mode_and_check_limit,
2448 2
2449 );
2450 }
2451
2452 /// Contested indexes without a Lock choice (item 23): the three method
2453 /// versions that read the resolution are selected by v14 only, so a v13
2454 /// replay keeps the shipped rules (a full poll for every contest, ties to
2455 /// the latest contender, a Lock vote accepted on any contest).
2456 #[test]
2457 fn no_locking_contests_are_selected_by_v14_only() {
2458 assert_eq!(
2459 PLATFORM_V13
2460 .drive_abci
2461 .methods
2462 .voting
2463 .check_for_ended_vote_polls,
2464 0
2465 );
2466 assert_eq!(
2467 PLATFORM_V14
2468 .drive_abci
2469 .methods
2470 .voting
2471 .check_for_ended_vote_polls,
2472 1
2473 );
2474 assert_eq!(
2475 PLATFORM_V13
2476 .drive_abci
2477 .validation_and_processing
2478 .state_transitions
2479 .masternode_vote_state_transition
2480 .state,
2481 0
2482 );
2483 assert_eq!(
2484 PLATFORM_V14
2485 .drive_abci
2486 .validation_and_processing
2487 .state_transitions
2488 .masternode_vote_state_transition
2489 .state,
2490 1
2491 );
2492 assert_eq!(
2493 PLATFORM_V13
2494 .drive
2495 .methods
2496 .document
2497 .insert_contested
2498 .add_contested_document_for_contract_operations,
2499 0
2500 );
2501 assert_eq!(
2502 PLATFORM_V14
2503 .drive
2504 .methods
2505 .document
2506 .insert_contested
2507 .add_contested_document_for_contract_operations,
2508 1
2509 );
2510 }
2511
2512 /// The ranked index keywords are gated by the meta-schema version, so v14
2513 /// must select meta-schema v3 while v13 stays on v2.
2514 #[test]
2515 fn ranked_index_keywords_are_gated_by_meta_schema_v3() {
2516 assert_eq!(
2517 PLATFORM_V13
2518 .dpp
2519 .contract_versions
2520 .document_type_versions
2521 .schema
2522 .document_type_schema,
2523 2
2524 );
2525 assert_eq!(
2526 PLATFORM_V14
2527 .dpp
2528 .contract_versions
2529 .document_type_versions
2530 .schema
2531 .document_type_schema,
2532 3
2533 );
2534 }
2535
2536 /// The ranked grammar lives in its own document-type parser generation
2537 /// rather than behind a version gate inside a shipped one, so v14 must
2538 /// select generation 3 while v13 stays on generation 2. Pinned here
2539 /// because it is the whole reason generations 0/1/2 can stay byte-identical
2540 /// to what consensus already ran: a historical block replayed at v13 is
2541 /// parsed by a generation that has never heard of the ranked keywords.
2542 /// The grove v4 cleanup gates (batch overwrite inspection + delete-tree
2543 /// actual-type cleanup) exist for the indexed trees that ranked indexes
2544 /// lay down, so v14 must select grove protocol 4 while v13 stays on 3.
2545 /// The gates are cost-neutral — they derive the old element from data the
2546 /// merk apply already loads — and the fee-constant tests pin identical
2547 /// fees on both sides of the boundary. Platform flows cannot themselves
2548 /// overwrite a ranked index (the flags are immutable on contract update
2549 /// and new indexes cannot be added to an existing document type), so the
2550 /// cleanup behavior itself is exercised by grovedb's own overwrite suites
2551 /// at the pinned revision; this test pins that v14 actually activates
2552 /// them.
2553 #[test]
2554 fn grove_v4_cleanup_gates_activate_at_v14() {
2555 assert_eq!(PLATFORM_V13.drive.grove_version.protocol_version, 3);
2556 assert_eq!(PLATFORM_V14.drive.grove_version.protocol_version, 4);
2557 }
2558
2559 #[test]
2560 fn ranked_grammar_gets_its_own_parser_generation() {
2561 assert_eq!(
2562 PLATFORM_V13
2563 .dpp
2564 .contract_versions
2565 .document_type_versions
2566 .class_method_versions
2567 .try_from_schema,
2568 2
2569 );
2570 assert_eq!(
2571 PLATFORM_V14
2572 .dpp
2573 .contract_versions
2574 .document_type_versions
2575 .class_method_versions
2576 .try_from_schema,
2577 3
2578 );
2579 }
2580
2581 /// The contested vote poll index cross-check changes accept/reject
2582 /// behavior for document create transitions, so it lives in v14's own
2583 /// validation table: a v13 node keeps running structure validation v0,
2584 /// which validates only the prefunded amount and ignores the index name.
2585 /// A change that made v13 non-zero here would retroactively reject
2586 /// transitions already in the chain.
2587 #[test]
2588 fn contested_index_cross_check_is_v14_only() {
2589 assert_eq!(
2590 PLATFORM_V13
2591 .drive_abci
2592 .validation_and_processing
2593 .state_transitions
2594 .batch_state_transition
2595 .document_create_transition_structure_validation,
2596 0
2597 );
2598 assert_eq!(
2599 PLATFORM_V14
2600 .drive_abci
2601 .validation_and_processing
2602 .state_transitions
2603 .batch_state_transition
2604 .document_create_transition_structure_validation,
2605 1
2606 );
2607 assert_eq!(
2608 PLATFORM_V13
2609 .drive_abci
2610 .validation_and_processing
2611 .state_transitions
2612 .batch_state_transition
2613 .document_create_transition_state_validation,
2614 1
2615 );
2616 assert_eq!(
2617 PLATFORM_V14
2618 .drive_abci
2619 .validation_and_processing
2620 .state_transitions
2621 .batch_state_transition
2622 .document_create_transition_state_validation,
2623 2
2624 );
2625 assert_eq!(
2626 PLATFORM_V13
2627 .drive
2628 .methods
2629 .document
2630 .insert_contested
2631 .add_contested_vote_subtree_for_non_identities_operations,
2632 0
2633 );
2634 assert_eq!(
2635 PLATFORM_V14
2636 .drive
2637 .methods
2638 .document
2639 .insert_contested
2640 .add_contested_vote_subtree_for_non_identities_operations,
2641 1
2642 );
2643 }
2644}