Skip to main content

hiero_sdk/system/
system_undelete_transaction.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hiero_sdk_proto::services;
4use hiero_sdk_proto::services::file_service_client::FileServiceClient;
5use hiero_sdk_proto::services::smart_contract_service_client::SmartContractServiceClient;
6use tonic::transport::Channel;
7
8use crate::protobuf::{
9    FromProtobuf,
10    ToProtobuf,
11};
12use crate::transaction::{
13    AnyTransactionData,
14    ChunkInfo,
15    ToSchedulableTransactionDataProtobuf,
16    ToTransactionDataProtobuf,
17    TransactionData,
18    TransactionExecute,
19};
20use crate::{
21    BoxGrpcFuture,
22    ContractId,
23    Error,
24    FileId,
25    Transaction,
26    ValidateChecksums,
27};
28
29/// Undelete a file or smart contract that was deleted by a [`SystemUndeleteTransaction`](crate::SystemUndeleteTransaction).
30pub type SystemUndeleteTransaction = Transaction<SystemUndeleteTransactionData>;
31
32/// Undelete a file or smart contract that was deleted by  [`SystemUndeleteTransaction`](crate::SystemUndeleteTransaction).
33#[derive(Debug, Clone, Default)]
34pub struct SystemUndeleteTransactionData {
35    file_id: Option<FileId>,
36    contract_id: Option<ContractId>,
37}
38
39impl SystemUndeleteTransaction {
40    /// Returns the contract ID to undelete.
41    #[must_use]
42    pub fn get_contract_id(&self) -> Option<ContractId> {
43        self.data().contract_id
44    }
45
46    /// Sets the contract ID to undelete.
47    pub fn contract_id(&mut self, id: impl Into<ContractId>) -> &mut Self {
48        let data = self.data_mut();
49        data.file_id = None;
50        data.contract_id = Some(id.into());
51        self
52    }
53
54    /// Returns the file ID to undelete.
55    #[must_use]
56    pub fn get_file_id(&self) -> Option<FileId> {
57        self.data().file_id
58    }
59
60    /// Sets the file ID to undelete.
61    pub fn file_id(&mut self, id: impl Into<FileId>) -> &mut Self {
62        let data = self.data_mut();
63        data.contract_id = None;
64        data.file_id = Some(id.into());
65        self
66    }
67}
68
69impl TransactionData for SystemUndeleteTransactionData {}
70
71impl TransactionExecute for SystemUndeleteTransactionData {
72    #[allow(deprecated)]
73    fn execute(
74        &self,
75        channel: Channel,
76        request: services::Transaction,
77    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
78        Box::pin(async move {
79            if self.file_id.is_some() {
80                FileServiceClient::new(channel).system_undelete(request).await
81            } else {
82                SmartContractServiceClient::new(channel).system_undelete(request).await
83            }
84        })
85    }
86}
87
88impl ValidateChecksums for SystemUndeleteTransactionData {
89    fn validate_checksums(&self, ledger_id: &crate::ledger_id::RefLedgerId) -> Result<(), Error> {
90        self.contract_id.validate_checksums(ledger_id)?;
91        self.file_id.validate_checksums(ledger_id)
92    }
93}
94
95impl ToTransactionDataProtobuf for SystemUndeleteTransactionData {
96    fn to_transaction_data_protobuf(
97        &self,
98        chunk_info: &ChunkInfo,
99    ) -> services::transaction_body::Data {
100        let _ = chunk_info.assert_single_transaction();
101
102        services::transaction_body::Data::SystemUndelete(self.to_protobuf())
103    }
104}
105
106impl ToSchedulableTransactionDataProtobuf for SystemUndeleteTransactionData {
107    fn to_schedulable_transaction_data_protobuf(
108        &self,
109    ) -> services::schedulable_transaction_body::Data {
110        services::schedulable_transaction_body::Data::SystemUndelete(self.to_protobuf())
111    }
112}
113
114impl From<SystemUndeleteTransactionData> for AnyTransactionData {
115    fn from(transaction: SystemUndeleteTransactionData) -> Self {
116        Self::SystemUndelete(transaction)
117    }
118}
119
120impl FromProtobuf<services::SystemUndeleteTransactionBody> for SystemUndeleteTransactionData {
121    fn from_protobuf(pb: services::SystemUndeleteTransactionBody) -> crate::Result<Self> {
122        use services::system_undelete_transaction_body::Id;
123        let (file_id, contract_id) = match pb.id {
124            Some(Id::FileId(it)) => (Some(FileId::from_protobuf(it)?), None),
125            Some(Id::ContractId(it)) => (None, Some(ContractId::from_protobuf(it)?)),
126            None => (None, None),
127        };
128
129        Ok(Self { file_id, contract_id })
130    }
131}
132
133impl ToProtobuf for SystemUndeleteTransactionData {
134    type Protobuf = services::SystemUndeleteTransactionBody;
135
136    fn to_protobuf(&self) -> Self::Protobuf {
137        let contract_id = self.contract_id.to_protobuf();
138        let file_id = self.file_id.to_protobuf();
139
140        let id = match (contract_id, file_id) {
141            (Some(contract_id), _) => {
142                Some(services::system_undelete_transaction_body::Id::ContractId(contract_id))
143            }
144
145            (_, Some(file_id)) => {
146                Some(services::system_undelete_transaction_body::Id::FileId(file_id))
147            }
148
149            _ => None,
150        };
151        services::SystemUndeleteTransactionBody { id }
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use expect_test::expect;
158    use hiero_sdk_proto::services;
159
160    use crate::protobuf::{
161        FromProtobuf,
162        ToProtobuf,
163    };
164    use crate::system::SystemUndeleteTransactionData;
165    use crate::transaction::test_helpers::{
166        check_body,
167        transaction_body,
168    };
169    use crate::{
170        AnyTransaction,
171        ContractId,
172        FileId,
173        SystemUndeleteTransaction,
174    };
175
176    const FILE_ID: FileId = FileId::new(0, 0, 444);
177    const CONTRACT_ID: ContractId = ContractId::new(0, 0, 444);
178
179    fn make_transaction_file() -> SystemUndeleteTransaction {
180        let mut tx = SystemUndeleteTransaction::new_for_tests();
181
182        tx.file_id(FILE_ID).freeze().unwrap();
183        tx
184    }
185
186    fn make_transaction_contract() -> SystemUndeleteTransaction {
187        let mut tx = SystemUndeleteTransaction::new_for_tests();
188
189        tx.contract_id(CONTRACT_ID).freeze().unwrap();
190        tx
191    }
192
193    #[test]
194    fn serialize_file() {
195        let tx = make_transaction_file();
196
197        let tx = transaction_body(tx);
198
199        let tx = check_body(tx);
200
201        expect![[r#"
202            SystemUndelete(
203                SystemUndeleteTransactionBody {
204                    id: Some(
205                        FileId(
206                            FileId {
207                                shard_num: 0,
208                                realm_num: 0,
209                                file_num: 444,
210                            },
211                        ),
212                    ),
213                },
214            )
215        "#]]
216        .assert_debug_eq(&tx)
217    }
218
219    #[test]
220    fn serialize_contract() {
221        let tx = make_transaction_contract();
222
223        let tx = transaction_body(tx);
224
225        let tx = check_body(tx);
226
227        expect![[r#"
228            SystemUndelete(
229                SystemUndeleteTransactionBody {
230                    id: Some(
231                        ContractId(
232                            ContractId {
233                                shard_num: 0,
234                                realm_num: 0,
235                                contract: Some(
236                                    ContractNum(
237                                        444,
238                                    ),
239                                ),
240                            },
241                        ),
242                    ),
243                },
244            )
245        "#]]
246        .assert_debug_eq(&tx)
247    }
248
249    #[test]
250    fn to_from_bytes_file() {
251        let tx = make_transaction_file();
252
253        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
254
255        let tx = transaction_body(tx);
256
257        let tx2 = transaction_body(tx2);
258
259        assert_eq!(tx, tx2);
260    }
261
262    #[test]
263    fn to_from_bytes_contract() {
264        let tx = make_transaction_contract();
265
266        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
267
268        let tx = transaction_body(tx);
269
270        let tx2 = transaction_body(tx2);
271
272        assert_eq!(tx, tx2);
273    }
274
275    #[test]
276    fn from_proto_body() {
277        let tx = services::SystemUndeleteTransactionBody {
278            id: Some(services::system_undelete_transaction_body::Id::FileId(FILE_ID.to_protobuf())),
279        };
280
281        let tx = SystemUndeleteTransactionData::from_protobuf(tx).unwrap();
282
283        assert_eq!(tx.file_id, Some(FILE_ID));
284        assert_eq!(tx.contract_id, None);
285    }
286
287    #[test]
288    fn get_set_file_id() {
289        let mut tx = SystemUndeleteTransaction::new();
290        tx.file_id(FILE_ID);
291
292        assert_eq!(tx.get_file_id(), Some(FILE_ID));
293    }
294
295    #[test]
296    #[should_panic]
297    fn get_set_file_id_frozen_panics() {
298        make_transaction_file().file_id(FILE_ID);
299    }
300
301    #[test]
302    fn get_set_contract_id() {
303        let mut tx = SystemUndeleteTransaction::new();
304        tx.contract_id(CONTRACT_ID);
305
306        assert_eq!(tx.get_contract_id(), Some(CONTRACT_ID));
307    }
308
309    #[test]
310    #[should_panic]
311    fn get_set_contract_id_frozen_panics() {
312        make_transaction_file().contract_id(CONTRACT_ID);
313    }
314}