drive/state_transition_action/batch/
mod.rs

1use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction;
2use crate::state_transition_action::batch::v0::BatchTransitionActionV0;
3use derive_more::From;
4use dpp::data_contract::accessors::v0::DataContractV0Getters;
5use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
6use dpp::fee::Credits;
7use dpp::identity::SecurityLevel;
8use dpp::platform_value::Identifier;
9use dpp::prelude::UserFeeIncrease;
10use dpp::ProtocolError;
11use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0;
12
13/// batched transition
14pub mod batched_transition;
15/// v0
16pub mod v0;
17
18#[cfg(test)]
19mod tests;
20
21/// documents batch transition action
22#[derive(Debug, Clone, From)]
23pub enum BatchTransitionAction {
24    /// v0
25    V0(BatchTransitionActionV0),
26}
27
28impl BatchTransitionAction {
29    /// owner id
30    pub fn owner_id(&self) -> Identifier {
31        match self {
32            BatchTransitionAction::V0(v0) => v0.owner_id,
33        }
34    }
35
36    /// transitions
37    pub fn transitions(&self) -> &Vec<BatchedTransitionAction> {
38        match self {
39            BatchTransitionAction::V0(v0) => &v0.transitions,
40        }
41    }
42
43    /// transitions
44    pub fn transitions_mut(&mut self) -> &mut Vec<BatchedTransitionAction> {
45        match self {
46            BatchTransitionAction::V0(v0) => &mut v0.transitions,
47        }
48    }
49
50    /// transitions
51    pub fn transitions_take(&mut self) -> Vec<BatchedTransitionAction> {
52        match self {
53            BatchTransitionAction::V0(v0) => std::mem::take(&mut v0.transitions),
54        }
55    }
56
57    /// transitions owned
58    pub fn transitions_owned(self) -> Vec<BatchedTransitionAction> {
59        match self {
60            BatchTransitionAction::V0(v0) => v0.transitions,
61        }
62    }
63
64    /// set transitions
65    pub fn set_transitions(&mut self, transitions: Vec<BatchedTransitionAction>) {
66        match self {
67            BatchTransitionAction::V0(v0) => v0.transitions = transitions,
68        }
69    }
70
71    /// fee multiplier
72    pub fn user_fee_increase(&self) -> UserFeeIncrease {
73        match self {
74            BatchTransitionAction::V0(transition) => transition.user_fee_increase,
75        }
76    }
77}
78
79impl BatchTransitionAction {
80    /// The sum of all purchases amount and all conflicting index collateral voting funds
81    pub fn all_used_balances(&self) -> Result<Option<Credits>, ProtocolError> {
82        match self {
83            BatchTransitionAction::V0(v0) => v0.all_used_balances(),
84        }
85    }
86
87    /// The sum of all purchases amounts for all purchase transitions in the batch
88    pub fn all_purchases_amount(&self) -> Result<Option<Credits>, ProtocolError> {
89        match self {
90            BatchTransitionAction::V0(v0) => v0.all_purchases_amount(),
91        }
92    }
93
94    /// The sum of all conflicting index collateral voting funds for all document create transitions in the batch
95    pub fn all_conflicting_index_collateral_voting_funds(
96        &self,
97    ) -> Result<Option<Credits>, ProtocolError> {
98        match self {
99            BatchTransitionAction::V0(v0) => v0.all_conflicting_index_collateral_voting_funds(),
100        }
101    }
102
103    /// Determines the security level requirements for the batch transition action.
104    ///
105    /// This method performs the following steps:
106    ///
107    /// 1. Retrieves all document types associated with the state transitions (STs) in the batch.
108    /// 2. For each document type, fetches its schema to determine its security level requirement.
109    ///    - If the schema specifies a security level, that is used.
110    ///    - Otherwise, a default security level is used.
111    ///
112    /// The method then determines the highest security level (which corresponds to the lowest
113    /// integer value of the `SecurityLevel` enum) across all documents affected by the state transitions.
114    /// This highest level becomes the signature requirement for the entire batch transition action.
115    ///
116    /// # Returns
117    ///
118    /// - Returns a `Result` containing a `Vec<SecurityLevel>` which is the list of security
119    ///   levels required for the batch transition action.
120    /// - Returns an `Err` of type `ProtocolError` if any error occurs during the process.
121    ///
122    /// # Examples
123    ///
124    /// ```ignore
125    /// // Assuming `batch_transition_action` is an instance of `DocumentsBatchTransitionAction`
126    /// let required_levels = batch_transition_action.contract_based_security_level_requirement()?;
127    /// ```
128    ///
129    pub fn combined_security_level_requirement(&self) -> Result<Vec<SecurityLevel>, ProtocolError> {
130        // Step 1: Get all document types for the ST
131        // Step 2: Get document schema for every type
132        // If schema has security level, use that, if not, use the default security level
133        // Find the highest level (lowest int value) of all documents - the ST's signature
134        // requirement is the highest level across all documents affected by the ST./
135        let mut highest_security_level = SecurityLevel::lowest_level();
136
137        for transition in self.transitions().iter() {
138            match transition {
139                BatchedTransitionAction::DocumentAction(document_transition) => {
140                    let document_type_name = document_transition.base().document_type_name();
141                    let data_contract_info = document_transition.base().data_contract_fetch_info();
142
143                    let document_type = data_contract_info
144                        .contract
145                        .document_type_for_name(document_type_name)?;
146
147                    let document_security_level = document_type.security_level_requirement();
148
149                    // lower enum representation means higher in security
150                    if document_security_level < highest_security_level {
151                        highest_security_level = document_security_level
152                    }
153                }
154                BatchedTransitionAction::TokenAction(_) => {
155                    // lower enum representation means higher in security
156                    if highest_security_level != SecurityLevel::MASTER {
157                        highest_security_level = SecurityLevel::CRITICAL
158                    }
159                }
160                BatchedTransitionAction::BumpIdentityDataContractNonce(_) => {}
161            }
162        }
163        Ok(if highest_security_level == SecurityLevel::MASTER {
164            vec![SecurityLevel::MASTER]
165        } else {
166            // this might seem wrong until you realize that master is 0, critical 1, etc
167            (SecurityLevel::CRITICAL as u8..=highest_security_level as u8)
168                .map(|security_level| SecurityLevel::try_from(security_level).unwrap())
169                .collect()
170        })
171    }
172}