Skip to main content

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