stellar_base/operations/
manage_data.rs

1use crate::account::DataValue;
2use crate::crypto::MuxedAccount;
3use crate::error::{Error, Result};
4use crate::operations::Operation;
5use crate::xdr;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct ManageDataOperation {
9    source_account: Option<MuxedAccount>,
10    data_name: String,
11    data_value: Option<DataValue>,
12}
13
14#[derive(Debug, Default)]
15pub struct ManageDataOperationBuilder {
16    source_account: Option<MuxedAccount>,
17    data_name: Option<String>,
18    data_value: Option<DataValue>,
19}
20
21impl ManageDataOperation {
22    /// Retrieves the operation source account.
23    pub fn source_account(&self) -> &Option<MuxedAccount> {
24        &self.source_account
25    }
26
27    /// Retrieves a reference to the operation source account.
28    pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
29        &mut self.source_account
30    }
31
32    /// Retrieves the operation data name.
33    pub fn data_name(&self) -> &str {
34        &self.data_name
35    }
36
37    /// Retrieves a mutable reference to the operation data name.
38    pub fn data_name_mut(&mut self) -> &mut str {
39        &mut self.data_name
40    }
41
42    /// Retrieves the operation data value.
43    pub fn data_value(&self) -> &Option<DataValue> {
44        &self.data_value
45    }
46
47    /// Retrieves a mutable reference to the operation data value.
48    pub fn data_value_mut(&mut self) -> &mut Option<DataValue> {
49        &mut self.data_value
50    }
51
52    /// Returns the xdr operation body.
53    pub fn to_xdr_operation_body(&self) -> Result<xdr::OperationBody> {
54        let data_name = self
55            .data_name
56            .as_bytes()
57            .to_vec()
58            .try_into()
59            .map_err(|_| Error::XdrError)?;
60        let data_value = self.data_value.as_ref().map(|d| d.to_xdr()).transpose()?;
61        let inner = xdr::ManageDataOp {
62            data_name,
63            data_value,
64        };
65        Ok(xdr::OperationBody::ManageData(inner))
66    }
67
68    /// Creates from the xdr operation body.
69    pub fn from_xdr_operation_body(
70        source_account: Option<MuxedAccount>,
71        x: &xdr::ManageDataOp,
72    ) -> Result<ManageDataOperation> {
73        let data_name = x.data_name.to_string();
74        let data_value = x.data_value.as_ref().map(DataValue::from_xdr).transpose()?;
75
76        Ok(ManageDataOperation {
77            source_account,
78            data_name,
79            data_value,
80        })
81    }
82}
83
84impl ManageDataOperationBuilder {
85    pub fn new() -> ManageDataOperationBuilder {
86        Default::default()
87    }
88
89    pub fn with_source_account<S>(mut self, source: S) -> ManageDataOperationBuilder
90    where
91        S: Into<MuxedAccount>,
92    {
93        self.source_account = Some(source.into());
94        self
95    }
96
97    pub fn with_data_name(mut self, name: String) -> ManageDataOperationBuilder {
98        self.data_name = Some(name);
99        self
100    }
101
102    pub fn with_data_value(mut self, value: Option<DataValue>) -> ManageDataOperationBuilder {
103        self.data_value = value;
104        self
105    }
106
107    pub fn build(self) -> Result<Operation> {
108        let data_name = self
109            .data_name
110            .ok_or_else(|| Error::InvalidOperation("missing manage data data name".to_string()))?;
111
112        Ok(Operation::ManageData(ManageDataOperation {
113            source_account: self.source_account,
114            data_name,
115            data_value: self.data_value,
116        }))
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use crate::account::DataValue;
123
124    use crate::network::Network;
125    use crate::operations::tests::*;
126    use crate::operations::Operation;
127    use crate::transaction::{Transaction, TransactionEnvelope, MIN_BASE_FEE};
128    use crate::xdr::{XDRDeserialize, XDRSerialize};
129
130    #[test]
131    fn test_manage_data() {
132        let kp = keypair0();
133        let value = DataValue::from_slice("value value".as_bytes()).unwrap();
134        let op = Operation::new_manage_data()
135            .with_data_name("TEST TEST".to_string())
136            .with_data_value(Some(value))
137            .build()
138            .unwrap();
139
140        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
141            .add_operation(op)
142            .into_transaction()
143            .unwrap();
144        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
145        let envelope = tx.to_envelope();
146        let xdr = envelope.xdr_base64().unwrap();
147        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAKAAAACVRFU1QgVEVTVAAAAAAAAAEAAAALdmFsdWUgdmFsdWUAAAAAAAAAAAHqLnLFAAAAQLxeb1DkXDTXi/rOffnHpyxuJhl8vN/GDMKLtxFFTGn5b99FNHmWUyUoxb4KTE9bBguIe33SEQ/npj32f2vt/gY=";
148        assert_eq!(expected, xdr);
149        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
150        assert_eq!(envelope, back);
151    }
152
153    #[test]
154    fn test_manage_data_with_source_account() {
155        let kp = keypair0();
156        let kp1 = keypair1();
157        let value = DataValue::from_slice("value value".as_bytes()).unwrap();
158        let op = Operation::new_manage_data()
159            .with_source_account(kp1.public_key())
160            .with_data_name("TEST TEST".to_string())
161            .with_data_value(Some(value))
162            .build()
163            .unwrap();
164
165        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
166            .add_operation(op)
167            .into_transaction()
168            .unwrap();
169        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
170        let envelope = tx.to_envelope();
171        let xdr = envelope.xdr_base64().unwrap();
172        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAEAAAAAJcrx2g/Hbs/ohF5CVFG7B5JJSJR+OqDKzDGK7dKHZH4AAAAKAAAACVRFU1QgVEVTVAAAAAAAAAEAAAALdmFsdWUgdmFsdWUAAAAAAAAAAAHqLnLFAAAAQBQKnwjKQ1RbYg0rk7G9VV1jHwM29YEp1EoOug960nTVWga6aFmPlQ0mDDudEsbSMq+9G8eYX5mcu9EHTjZUBQI=";
173        assert_eq!(expected, xdr);
174        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
175        assert_eq!(envelope, back);
176    }
177}