drive_abci/execution/validation/state_transition/transformer/
mod.rs

1use crate::error::execution::ExecutionError;
2use crate::error::Error;
3use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext;
4use crate::execution::validation::state_transition::address_credit_withdrawal::StateTransitionAddressCreditWithdrawalTransitionActionTransformer;
5use crate::execution::validation::state_transition::address_funding_from_asset_lock::StateTransitionAddressFundingFromAssetLockTransitionActionTransformer;
6use crate::execution::validation::state_transition::address_funds_transfer::StateTransitionAddressFundsTransferTransitionActionTransformer;
7use crate::execution::validation::state_transition::identity_create::StateTransitionActionTransformerForIdentityCreateTransitionV0;
8use crate::execution::validation::state_transition::identity_create_from_addresses::StateTransitionActionTransformerForIdentityCreateFromAddressesTransitionV0;
9use crate::execution::validation::state_transition::identity_top_up::StateTransitionIdentityTopUpTransitionActionTransformer;
10use crate::execution::validation::state_transition::shield::StateTransitionShieldTransitionActionTransformer;
11use crate::execution::validation::state_transition::shield_from_asset_lock::StateTransitionShieldFromAssetLockTransitionActionTransformer;
12use crate::execution::validation::state_transition::shielded_transfer::StateTransitionShieldedTransferTransitionActionTransformer;
13use crate::execution::validation::state_transition::shielded_withdrawal::StateTransitionShieldedWithdrawalTransitionActionTransformer;
14use crate::execution::validation::state_transition::unshield::StateTransitionUnshieldTransitionActionTransformer;
15use crate::execution::validation::state_transition::ValidationMode;
16use crate::platform_types::platform::PlatformRef;
17use crate::rpc::core::CoreRPCLike;
18use dpp::address_funds::PlatformAddress;
19use dpp::block::block_info::BlockInfo;
20use dpp::fee::Credits;
21use dpp::prelude::{AddressNonce, ConsensusValidationResult};
22use dpp::serialization::Signable;
23use dpp::state_transition::StateTransition;
24use drive::grovedb::TransactionArg;
25use drive::state_transition_action::identity::identity_topup_from_addresses::IdentityTopUpFromAddressesTransitionAction;
26use drive::state_transition_action::StateTransitionAction;
27use std::collections::BTreeMap;
28
29/// A trait for validating state transitions within a blockchain.
30pub trait StateTransitionActionTransformer {
31    /// A trait for transforming a raw `TransactionArg` into a typed `StateTransitionAction`.
32    ///
33    /// This is primarily intended for **testing**, internal tooling, and controlled validation flows.
34    /// In production, the transformation is normally performed within `validate_state`, and this
35    /// method should not be invoked directly.
36    ///
37    /// ## Versioning Note
38    /// This trait is intentionally **not versioned**.
39    /// If the structure of `transform_into_action` ever needs to change, a new trait should be
40    /// introduced rather than modifying this one to preserve API stability.
41    ///
42    /// # Type Parameters
43    /// * `C` – A type implementing the [`CoreRPCLike`] trait.
44    ///
45    /// # Arguments
46    /// * `platform` – A platform reference implementing `CoreRPCLike`.
47    /// * `block_info` – Information about the current block.
48    /// * `remaining_address_input_balances` – A map of input addresses to their (nonce, balance)
49    ///   tuples used during partial validation.
50    /// * `validation_mode` – The current validation mode controlling the strictness of checks.
51    /// * `execution_context` – The execution context for the state transition.
52    /// * `tx` – The raw transaction argument to be transformed.
53    ///
54    /// # Returns
55    /// A `Result` containing:
56    /// * `ConsensusValidationResult<StateTransitionAction>` on success, or
57    /// * `Error` if the action could not be created or validated.
58    fn transform_into_action<C: CoreRPCLike>(
59        &self,
60        platform: &PlatformRef<C>,
61        block_info: &BlockInfo,
62        remaining_address_input_balances: &Option<
63            BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
64        >,
65        validation_mode: ValidationMode,
66        execution_context: &mut StateTransitionExecutionContext,
67        tx: TransactionArg,
68    ) -> Result<ConsensusValidationResult<StateTransitionAction>, Error>;
69}
70
71impl StateTransitionActionTransformer for StateTransition {
72    fn transform_into_action<C: CoreRPCLike>(
73        &self,
74        platform: &PlatformRef<C>,
75        block_info: &BlockInfo,
76        remaining_address_input_balances: &Option<
77            BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
78        >,
79        validation_mode: ValidationMode,
80        execution_context: &mut StateTransitionExecutionContext,
81        tx: TransactionArg,
82    ) -> Result<ConsensusValidationResult<StateTransitionAction>, Error> {
83        match self {
84            StateTransition::DataContractCreate(st) => st.transform_into_action(
85                platform,
86                block_info,
87                remaining_address_input_balances,
88                validation_mode,
89                execution_context,
90                tx,
91            ),
92            StateTransition::DataContractUpdate(st) => st.transform_into_action(
93                platform,
94                block_info,
95                remaining_address_input_balances,
96                validation_mode,
97                execution_context,
98                tx,
99            ),
100            StateTransition::IdentityCreate(st) => {
101                let signable_bytes = self.signable_bytes()?;
102                st.transform_into_action_for_identity_create_transition(
103                    platform,
104                    signable_bytes,
105                    validation_mode,
106                    execution_context,
107                    tx,
108                )
109            }
110            StateTransition::IdentityUpdate(st) => st.transform_into_action(
111                platform,
112                block_info,
113                remaining_address_input_balances,
114                validation_mode,
115                execution_context,
116                tx,
117            ),
118            StateTransition::IdentityTopUp(st) => {
119                let signable_bytes = self.signable_bytes()?;
120                st.transform_into_action_for_identity_top_up_transition(
121                    platform,
122                    signable_bytes,
123                    validation_mode,
124                    execution_context,
125                    tx,
126                )
127            }
128            StateTransition::IdentityCreditWithdrawal(st) => st.transform_into_action(
129                platform,
130                block_info,
131                remaining_address_input_balances,
132                validation_mode,
133                execution_context,
134                tx,
135            ),
136            StateTransition::Batch(st) => st.transform_into_action(
137                platform,
138                block_info,
139                remaining_address_input_balances,
140                validation_mode,
141                execution_context,
142                tx,
143            ),
144            StateTransition::IdentityCreditTransfer(st) => st.transform_into_action(
145                platform,
146                block_info,
147                remaining_address_input_balances,
148                validation_mode,
149                execution_context,
150                tx,
151            ),
152            StateTransition::MasternodeVote(st) => st.transform_into_action(
153                platform,
154                block_info,
155                remaining_address_input_balances,
156                validation_mode,
157                execution_context,
158                tx,
159            ),
160            StateTransition::IdentityCreditTransferToAddresses(st) => st.transform_into_action(
161                platform,
162                block_info,
163                remaining_address_input_balances,
164                validation_mode,
165                execution_context,
166                tx,
167            ),
168            StateTransition::IdentityCreateFromAddresses(st) => {
169                let Some(remaining_address_input_balances) = remaining_address_input_balances
170                else {
171                    return Err(Error::Execution(ExecutionError::CorruptedCodeExecution(
172                        "we must have remaining address input balances",
173                    )));
174                };
175                st.transform_into_action_for_identity_create_from_addresses_transition(
176                    platform,
177                    remaining_address_input_balances.clone(),
178                )
179            }
180            StateTransition::IdentityTopUpFromAddresses(st) => {
181                let Some(remaining_address_input_balances) = remaining_address_input_balances
182                else {
183                    return Err(Error::Execution(ExecutionError::CorruptedCodeExecution(
184                        "we must have remaining address input balances",
185                    )));
186                };
187                Ok(
188                    IdentityTopUpFromAddressesTransitionAction::try_from_transition(
189                        st,
190                        remaining_address_input_balances.clone(),
191                    )
192                    .map(|action| action.into()),
193                )
194            }
195            StateTransition::AddressFundsTransfer(st) => {
196                let Some(remaining_address_input_balances) = remaining_address_input_balances
197                else {
198                    return Err(Error::Execution(ExecutionError::CorruptedCodeExecution(
199                        "we must have remaining address input balances",
200                    )));
201                };
202                st.transform_into_action_for_address_funds_transfer_transition(
203                    platform,
204                    remaining_address_input_balances.clone(),
205                )
206            }
207            StateTransition::AddressFundingFromAssetLock(st) => {
208                let Some(remaining_address_input_balances) = remaining_address_input_balances
209                else {
210                    return Err(Error::Execution(ExecutionError::CorruptedCodeExecution(
211                        "we must have remaining address input balances",
212                    )));
213                };
214                let signable_bytes = self.signable_bytes()?;
215                st.transform_into_action_for_address_funding_from_asset_lock_transition(
216                    platform,
217                    signable_bytes,
218                    remaining_address_input_balances.clone(),
219                    validation_mode,
220                    execution_context,
221                    tx,
222                )
223            }
224            StateTransition::AddressCreditWithdrawal(st) => {
225                let Some(remaining_address_input_balances) = remaining_address_input_balances
226                else {
227                    return Err(Error::Execution(ExecutionError::CorruptedCodeExecution(
228                        "we must have remaining address input balances",
229                    )));
230                };
231                st.transform_into_action_for_address_credit_withdrawal_transition(
232                    platform,
233                    block_info,
234                    remaining_address_input_balances.clone(),
235                )
236            }
237            StateTransition::Shield(st) => {
238                let Some(remaining_address_input_balances) = remaining_address_input_balances
239                else {
240                    return Err(Error::Execution(ExecutionError::CorruptedCodeExecution(
241                        "we must have remaining address input balances",
242                    )));
243                };
244                st.transform_into_action_for_shield_transition(
245                    platform,
246                    remaining_address_input_balances.clone(),
247                    block_info,
248                    execution_context,
249                    tx,
250                )
251            }
252            StateTransition::ShieldedTransfer(st) => st
253                .transform_into_action_for_shielded_transfer_transition(
254                    platform,
255                    block_info,
256                    execution_context,
257                    tx,
258                ),
259            StateTransition::Unshield(st) => st.transform_into_action_for_unshield_transition(
260                platform,
261                block_info,
262                execution_context,
263                tx,
264            ),
265            StateTransition::ShieldFromAssetLock(st) => {
266                let signable_bytes = self.signable_bytes()?;
267                st.transform_into_action_for_shield_from_asset_lock_transition(
268                    platform,
269                    signable_bytes,
270                    validation_mode,
271                    block_info,
272                    execution_context,
273                    tx,
274                )
275            }
276            StateTransition::ShieldedWithdrawal(st) => st
277                .transform_into_action_for_shielded_withdrawal_transition(
278                    platform,
279                    block_info,
280                    execution_context,
281                    tx,
282                ),
283        }
284    }
285}