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