drive/state_transition_action/shielded/shield/
mod.rs

1/// transformer
2pub mod transformer;
3/// v0
4pub mod v0;
5
6use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0;
7use crate::state_transition_action::shielded::ShieldedActionNote;
8use derive_more::From;
9use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress};
10use dpp::fee::Credits;
11use dpp::prelude::{AddressNonce, UserFeeIncrease};
12use std::collections::BTreeMap;
13
14/// Shield transition action
15#[derive(Debug, Clone, From)]
16pub enum ShieldTransitionAction {
17    /// v0
18    V0(ShieldTransitionActionV0),
19}
20
21impl ShieldTransitionAction {
22    /// Get inputs with remaining balance
23    pub fn inputs_with_remaining_balance(
24        &self,
25    ) -> &BTreeMap<PlatformAddress, (AddressNonce, Credits)> {
26        match self {
27            ShieldTransitionAction::V0(transition) => &transition.inputs_with_remaining_balance,
28        }
29    }
30    /// Get the shield amount
31    pub fn shield_amount(&self) -> Credits {
32        match self {
33            ShieldTransitionAction::V0(transition) => transition.shield_amount,
34        }
35    }
36    /// Get notes
37    pub fn notes(&self) -> &[ShieldedActionNote] {
38        match self {
39            ShieldTransitionAction::V0(transition) => &transition.notes,
40        }
41    }
42    /// fee multiplier
43    pub fn user_fee_increase(&self) -> UserFeeIncrease {
44        match self {
45            ShieldTransitionAction::V0(transition) => transition.user_fee_increase,
46        }
47    }
48    /// fee strategy
49    pub fn fee_strategy(&self) -> &AddressFundsFeeStrategy {
50        match self {
51            ShieldTransitionAction::V0(transition) => &transition.fee_strategy,
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use dpp::address_funds::fee_strategy::AddressFundsFeeStrategyStep;
60
61    fn make_note() -> ShieldedActionNote {
62        ShieldedActionNote {
63            nullifier: [0x11; 32],
64            cmx: [0x22; 32],
65            encrypted_note: vec![0xAB, 0xCD, 0xEF],
66        }
67    }
68
69    fn make_action() -> ShieldTransitionAction {
70        let addr = PlatformAddress::P2pkh([0xAA; 20]);
71        let mut inputs = BTreeMap::new();
72        inputs.insert(addr, (3_u32, 10000_u64));
73
74        let v0 = ShieldTransitionActionV0 {
75            inputs_with_remaining_balance: inputs,
76            shield_amount: 5000,
77            notes: vec![make_note(), make_note()],
78            fee_strategy: vec![AddressFundsFeeStrategyStep::DeductFromInput(0)],
79            user_fee_increase: 2,
80            current_total_balance: 50000,
81        };
82        ShieldTransitionAction::from(v0)
83    }
84
85    #[test]
86    fn test_from_v0() {
87        let action = make_action();
88        assert!(matches!(action, ShieldTransitionAction::V0(_)));
89    }
90
91    #[test]
92    fn test_inputs_with_remaining_balance() {
93        let action = make_action();
94        let inputs = action.inputs_with_remaining_balance();
95        assert_eq!(inputs.len(), 1);
96        let addr = PlatformAddress::P2pkh([0xAA; 20]);
97        let (nonce, balance) = inputs.get(&addr).unwrap();
98        assert_eq!(*nonce, 3);
99        assert_eq!(*balance, 10000);
100    }
101
102    #[test]
103    fn test_shield_amount() {
104        let action = make_action();
105        assert_eq!(action.shield_amount(), 5000);
106    }
107
108    #[test]
109    fn test_notes() {
110        let action = make_action();
111        let notes = action.notes();
112        assert_eq!(notes.len(), 2);
113        assert_eq!(notes[0].nullifier, [0x11; 32]);
114        assert_eq!(notes[0].cmx, [0x22; 32]);
115        assert_eq!(notes[0].encrypted_note, vec![0xAB, 0xCD, 0xEF]);
116    }
117
118    #[test]
119    fn test_user_fee_increase() {
120        let action = make_action();
121        assert_eq!(action.user_fee_increase(), 2);
122    }
123
124    #[test]
125    fn test_fee_strategy() {
126        let action = make_action();
127        let strategy = action.fee_strategy();
128        assert_eq!(strategy.len(), 1);
129        assert!(matches!(
130            strategy[0],
131            AddressFundsFeeStrategyStep::DeductFromInput(0)
132        ));
133    }
134
135    #[test]
136    fn test_empty_notes() {
137        let v0 = ShieldTransitionActionV0 {
138            inputs_with_remaining_balance: BTreeMap::new(),
139            shield_amount: 0,
140            notes: vec![],
141            fee_strategy: vec![],
142            user_fee_increase: 0,
143            current_total_balance: 0,
144        };
145        let action = ShieldTransitionAction::from(v0);
146        assert!(action.notes().is_empty());
147        assert_eq!(action.shield_amount(), 0);
148    }
149
150    #[test]
151    fn test_clone() {
152        let action = make_action();
153        let cloned = action.clone();
154        assert_eq!(cloned.shield_amount(), 5000);
155        assert_eq!(cloned.notes().len(), 2);
156        assert_eq!(cloned.user_fee_increase(), 2);
157    }
158
159    #[test]
160    fn test_debug() {
161        let action = make_action();
162        let debug_str = format!("{:?}", action);
163        assert!(debug_str.contains("V0"));
164    }
165}