Skip to main content

hiero_sdk/address_book/
node_delete_transaction.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use hiero_sdk_proto::services;
4use hiero_sdk_proto::services::address_book_service_client::AddressBookServiceClient;
5use tonic::transport::Channel;
6
7use crate::ledger_id::RefLedgerId;
8use crate::protobuf::FromProtobuf;
9use crate::transaction::{
10    AnyTransactionData,
11    ChunkInfo,
12    ToSchedulableTransactionDataProtobuf,
13    ToTransactionDataProtobuf,
14    TransactionData,
15    TransactionExecute,
16};
17use crate::{
18    BoxGrpcFuture,
19    Error,
20    ToProtobuf,
21    Transaction,
22    ValidateChecksums,
23};
24
25/// A transaction body to delete a node from the network address book.
26///
27/// This transaction body SHALL be considered a "privileged transaction".
28///
29/// - A `NodeDeleteTransactionBody` MUST be signed by the governing council.
30/// - Upon success, the address book entry SHALL enter a "pending delete"
31///    state.
32/// - All address book entries pending deletion SHALL be removed from the
33///    active network configuration during the next `freeze` transaction with
34///    the field `freeze_type` set to `PREPARE_UPGRADE`.<br/>
35/// - A deleted address book node SHALL be removed entirely from network state.
36/// - A deleted address book node identifier SHALL NOT be reused.
37///
38/// ### Record Stream Effects
39/// Upon completion the "deleted" `node_id` SHALL be in the transaction
40/// receipt.
41pub type NodeDeleteTransaction = Transaction<NodeDeleteTransactionData>;
42
43/// A transaction body to delete a node from the network address book.
44#[derive(Debug, Clone, Default)]
45pub struct NodeDeleteTransactionData {
46    /// A consensus node identifier in the network state.
47    node_id: u64,
48}
49
50impl NodeDeleteTransaction {
51    /// Returns the node ID associated with the node to be deleted.
52    #[must_use]
53    pub fn get_node_id(&self) -> u64 {
54        self.data().node_id
55    }
56
57    /// Sets the node ID associated with the node to be deleted.
58    pub fn node_id(&mut self, node_id: u64) -> &mut Self {
59        self.data_mut().node_id = node_id;
60        self
61    }
62}
63
64impl TransactionData for NodeDeleteTransactionData {}
65
66impl TransactionExecute for NodeDeleteTransactionData {
67    fn execute(
68        &self,
69        channel: Channel,
70        request: services::Transaction,
71    ) -> BoxGrpcFuture<'_, services::TransactionResponse> {
72        Box::pin(async { AddressBookServiceClient::new(channel).delete_node(request).await })
73    }
74}
75
76impl ValidateChecksums for NodeDeleteTransactionData {
77    fn validate_checksums(&self, _ledger_id: &RefLedgerId) -> Result<(), Error> {
78        Ok(())
79    }
80}
81
82impl ToTransactionDataProtobuf for NodeDeleteTransactionData {
83    fn to_transaction_data_protobuf(
84        &self,
85        chunk_info: &ChunkInfo,
86    ) -> services::transaction_body::Data {
87        let _ = chunk_info.assert_single_transaction();
88
89        services::transaction_body::Data::NodeDelete(self.to_protobuf())
90    }
91}
92
93impl ToSchedulableTransactionDataProtobuf for NodeDeleteTransactionData {
94    fn to_schedulable_transaction_data_protobuf(
95        &self,
96    ) -> services::schedulable_transaction_body::Data {
97        services::schedulable_transaction_body::Data::NodeDelete(self.to_protobuf())
98    }
99}
100
101impl From<NodeDeleteTransactionData> for AnyTransactionData {
102    fn from(transaction: NodeDeleteTransactionData) -> Self {
103        Self::NodeDelete(transaction)
104    }
105}
106
107impl FromProtobuf<services::NodeDeleteTransactionBody> for NodeDeleteTransactionData {
108    fn from_protobuf(pb: services::NodeDeleteTransactionBody) -> crate::Result<Self> {
109        Ok(Self { node_id: pb.node_id })
110    }
111}
112
113impl ToProtobuf for NodeDeleteTransactionData {
114    type Protobuf = services::NodeDeleteTransactionBody;
115
116    fn to_protobuf(&self) -> Self::Protobuf {
117        services::NodeDeleteTransactionBody { node_id: self.node_id }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use expect_test::expect_file;
124    use hiero_sdk_proto::services;
125
126    use super::NodeDeleteTransaction;
127    use crate::address_book::NodeDeleteTransactionData;
128    use crate::protobuf::FromProtobuf;
129    use crate::transaction::test_helpers::{
130        check_body,
131        transaction_body,
132    };
133    use crate::AnyTransaction;
134
135    fn make_transaction() -> NodeDeleteTransaction {
136        let mut tx = NodeDeleteTransaction::new_for_tests();
137
138        tx.node_id(1).freeze().unwrap();
139
140        tx
141    }
142
143    #[test]
144    fn serialize() {
145        let tx = make_transaction();
146
147        let tx = transaction_body(tx);
148
149        let tx = check_body(tx);
150
151        expect_file!["./snapshots/node_delete_transaction/serialize.txt"].assert_debug_eq(&tx);
152    }
153
154    #[test]
155    fn to_from_bytes() {
156        let tx = make_transaction();
157
158        let tx2 = AnyTransaction::from_bytes(&tx.to_bytes().unwrap()).unwrap();
159
160        let tx = transaction_body(tx);
161        let tx2 = transaction_body(tx2);
162
163        assert_eq!(tx, tx2)
164    }
165
166    #[test]
167    fn from_proto_body() {
168        let tx = services::NodeDeleteTransactionBody { node_id: 1 };
169
170        let data = NodeDeleteTransactionData::from_protobuf(tx).unwrap();
171
172        assert_eq!(data.node_id, 1);
173    }
174
175    #[test]
176    fn get_set_node_id() {
177        let mut tx = NodeDeleteTransaction::new();
178        tx.node_id(1);
179
180        assert_eq!(tx.get_node_id(), 1);
181    }
182
183    #[test]
184    #[should_panic]
185    fn get_set_node_id_frozen_panic() {
186        make_transaction().node_id(1);
187    }
188}