diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs index 9266e6938f8..9fa64c4609e 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs @@ -1196,6 +1196,11 @@ fn parse_indices( // storage level), so two indexes sharing a grid on one field share one // level's subtrees — and a level cannot have two lifecycles. Identical // grids must declare identical TTLs (including both declaring none). + // + // Document type generations 1-2 (protocol versions 9-13) run this loop too, but only the + // generation 3 index grammar admits `timeRange`, so every index they parse has + // `time_range: None` and the loop changes nothing for them. Generation 0 (protocol + // versions 1-8) parses its indices inline and never reaches this loop. for (name_a, index_a) in indices.iter() { let Some(transform_a) = &index_a.time_range else { continue; @@ -1461,7 +1466,12 @@ fn parse_token_costs( .transpose()? .unwrap_or(DocumentActionTokenEffect::TransferTokenToContractOwner); // Whether a transition may skip the token payment and have its signer pay - // the gas in credits instead (the v3 meta-schema admits the flag) + // the gas in credits instead. Only the v3 meta-schema admits the flag. + // Document type generations 1-2 (protocol versions 9-13) also run this + // parser, but their meta-schemas (v0-v2) set `additionalProperties: false` + // on `documentActionTokenCost`, so no contract they accept carries the key + // and this reads `false` for them, as before the flag existed. Generation 0 + // (protocol versions 1-8) never reaches this parser. let optional = action_cost .get_optional_bool("optional")? .unwrap_or_default(); diff --git a/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs index 2a13cc17780..0c07f6ecbe0 100644 --- a/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs @@ -272,7 +272,9 @@ where // Withdrawal transactions pooled in this block (or left over from a backlog) wait for // the next block to sign them. Ask Tenderdash for that block right away instead of - // after the empty-block interval. + // after the empty-block interval. Added in place to this shipped generation: the read + // is unbilled and only sets a hint for Tenderdash, so it changes no fee, state or app + // hash at any protocol version. let propose_next_block_immediately = self.has_pending_withdrawal_work(Some(transaction), platform_version)?; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/balance/v0/mod.rs index b3e93ea69ce..bdabab16e3d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/balance/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/balance/v0/mod.rs @@ -65,7 +65,10 @@ impl MasternodeVoteTransitionBalanceValidationV0 for MasternodeVoteTransition { // What executing the vote deducts from the fund. Until 4.2 the vote's minimum fee was // required here instead, a smaller amount, so a fund between the two passed this check - // and the vote failed inside execution. + // and the vote failed inside execution. Edited in place: it cannot change a block at any + // protocol version, because a vote refused here is refused unpaid and a vote that failed + // inside execution was an internal error, and both are left out of every block (see the + // prefunded balance pre-check in the state transition processor). let single_vote_cost = platform_version .fee_version .vote_resolution_fund_fees diff --git a/packages/rs-drive/src/drive/document/index_level_tree_types.rs b/packages/rs-drive/src/drive/document/index_level_tree_types.rs index 2245319577f..dd9593a88d8 100644 --- a/packages/rs-drive/src/drive/document/index_level_tree_types.rs +++ b/packages/rs-drive/src/drive/document/index_level_tree_types.rs @@ -224,6 +224,15 @@ pub(crate) fn time_range_index_keys<'a>( /// × stored/indexOnly): the insert side creates the tree and the delete /// side emits `EstimatedLayerInformation` describing it, and any drift /// produces dry-run fees that disagree with applied fees. +/// +/// Shipped generations depend on this function: +/// `add_reference_for_index_level_for_contract_operations` v0 (protocol +/// versions 1-14) and `remove_reference_for_index_level_for_contract_operations` +/// v0 (protocol versions 1-13) call it for every stored-type index terminal; +/// protocol version 14's remove-reference v1 calls it too. +/// Changing what it returns for an index shape protocol versions 1-13 can +/// declare changes the trees and fees of those versions; make such a change a +/// new versioned method instead of editing this function. pub(crate) fn terminal_member_tree_type(index_type: &IndexLevelTypeInfo) -> TreeType { let count_provable = matches!( index_type.countable, diff --git a/packages/rs-drive/src/drive/document/ranked_index_tree_type.rs b/packages/rs-drive/src/drive/document/ranked_index_tree_type.rs index a514cc63581..c7b1f630c47 100644 --- a/packages/rs-drive/src/drive/document/ranked_index_tree_type.rs +++ b/packages/rs-drive/src/drive/document/ranked_index_tree_type.rs @@ -127,6 +127,10 @@ pub(crate) fn ranked_property_name_tree_type( /// Callers pass the `has_index_with_type()` of the level *named after the /// property* — `None` for pure prefix levels, which resolve to /// `(NormalTree, [])`. +/// +/// Shipped generations depend on this function through +/// [`property_name_tree_type_and_ranked_axes_for_level`]: see the note there +/// before changing what it returns. pub(crate) fn property_name_tree_type_and_ranked_axes( index_level_info: Option<&IndexLevelTypeInfo>, ) -> Result<(TreeType, Vec), Error> { @@ -163,6 +167,14 @@ pub(crate) fn property_name_tree_type_and_ranked_axes( /// rs-dpp's structural validation guarantees no index terminates at a /// grouping or propagating level; both fail closed here on a stamped /// terminator rather than pick one of two contradictory layouts. +/// +/// Shipped generations depend on this function: the `insert_contract` v0 and +/// `update_contract` v0 operations call it to choose the tree type of every +/// top-level index level they create, and every later generation of both +/// composes those operations, so every protocol version reaches it. Changing what it returns +/// for an index level protocol versions 1-13 can declare changes the trees +/// and fees of those versions; make such a change a new versioned method +/// instead of editing this function. pub(crate) fn property_name_tree_type_and_ranked_axes_for_level( level: &IndexLevel, ) -> Result<(TreeType, Vec), Error> { diff --git a/packages/rs-platform-value/src/eq.rs b/packages/rs-platform-value/src/eq.rs index f32943f1a70..d76c6121f06 100644 --- a/packages/rs-platform-value/src/eq.rs +++ b/packages/rs-platform-value/src/eq.rs @@ -159,6 +159,13 @@ impl Value { /// stored at a narrower width, or an object whose members were /// reordered by schema position, still compares equal. /// * Otherwise falls back to normal `==` (`PartialEq`) behaviour. + /// + /// Shipped generations call this at every protocol version: the document + /// replace transition transformer v0 uses it to decide which fields a + /// replace changed, and `is_equal_ignoring_timestamps` v0 uses it when a + /// client verifies a state transition proof. A change to its result for + /// some pair of values changes their output everywhere; make such a change + /// a new versioned method instead of editing this function. pub fn equal_underlying_data(&self, other: &Value) -> bool { // 1) bytes-like cross-variant equality if let (Ok(a), Ok(b)) = (self.as_bytes_slice(), other.as_bytes_slice()) {