hedera_rust_client/
query.rs1use crate::client::Client;
2use crate::error::HederaError;
3use crate::executor::{ProtoRequest, Request, Response};
4
5use crate::proto::{services, ToProto};
6use crate::query_header::QueryHeader;
7use crate::response_type::ResponseType;
8use crate::signed_transaction::SignedTransaction;
9use crate::status::Status;
10use crate::transaction_body::TransactionBody;
11use crate::transaction_id::TransactionId;
12use crate::AccountId;
13use crate::Hbar;
14
15pub fn query_make_request_header(
16 query: &Query,
17 query_header: &mut QueryHeader,
18) -> Result<(), HederaError> {
19 if query.is_payment_required && !query.payment_transactions.is_empty() {
20 query_header.payment =
21 Some(query.payment_transactions[query.next_payment_transaction_index].clone())
22 }
23 query_header.response_type = ResponseType::AnswerOnly;
24 Ok(())
25}
26
27pub fn cost_query_make_request_header(
28 query_header: &mut QueryHeader,
29 client: &Client,
30) -> Result<(), HederaError> {
31 let payment_transaction = query_make_payment_transaction(None, None, client, None)?;
32 query_header.payment = Some(payment_transaction);
33 query_header.response_type = ResponseType::CostAnswer;
34 Ok(())
35}
36
37pub fn query_make_request(request: &mut Request) -> Result<ProtoRequest, HederaError> {
38 let query = request.get_query_mut()?;
39 Ok(ProtoRequest::Query(query.services.clone()))
40}
41
42#[allow(dead_code)]
43pub fn query_advance_request(request: &mut Request) -> Result<(), HederaError> {
44 let query = request.get_query_mut()?;
45 if query.is_payment_required && !query.payment_transactions.is_empty() {
46 query.next_payment_transaction_index =
47 (query.next_payment_transaction_index + 1) % query.payment_transactions.len();
48 }
49 Ok(())
50}
51
52pub fn cost_query_advance_request(request: &mut Request) -> Result<(), HederaError> {
53 let query = request.get_query_mut()?;
54 query.next_payment_transaction_index =
55 (query.next_payment_transaction_index + 1) % query.node_account_ids.len();
56 Ok(())
57}
58
59pub fn query_should_retry(status: &Status, _response: &Response) -> bool {
60 *status == Status::Busy
61}
62
63#[allow(dead_code)]
64pub fn query_get_node_account_id(request: &Request) -> Result<AccountId, HederaError> {
65 let query = request.get_query()?;
66 if !query.node_account_ids.is_empty() {
67 let account_id: AccountId =
68 query.node_account_ids[query.next_payment_transaction_index].clone();
69 return Ok(account_id);
70 }
71 return Err(HederaError::ValueNotSet("node AccountId's".to_string()));
72}
73
74pub fn cost_query_get_node_account_id(request: &Request) -> Result<AccountId, HederaError> {
75 let query = request.get_query()?;
76 let account_id: AccountId =
77 query.node_account_ids[query.next_payment_transaction_index].clone();
78 Ok(account_id)
79}
80
81pub fn query_make_payment_transaction(
82 transaction_id: Option<TransactionId>,
83 node_account_id: Option<AccountId>,
84 client: &Client,
85 cost: Option<Hbar>,
86) -> Result<services::Transaction, HederaError> {
87 let mut account_amounts = Vec::new();
88 if let Some(node_account_id) = &node_account_id {
89 let cost = match cost {
90 Some(cost) => cost,
91 None => return Err(HederaError::ValueNotSet("cost".to_string())),
92 };
93 let cost = cost.as_tinybar();
94 account_amounts.push(services::AccountAmount {
95 account_id: Some(node_account_id.to_proto()?),
96 amount: cost,
97 is_approval: false,
98 });
99 account_amounts.push(services::AccountAmount {
100 account_id: Some(client.operator_account_id().to_proto()?),
101 amount: -cost,
102 is_approval: false,
103 });
104 }
105 let mut body = TransactionBody::new();
106 body.transaction_id = transaction_id;
107 body.node_account_id = node_account_id;
108 body.transaction_fee = Hbar::new(1.0);
109 body.data = Some(services::transaction_body::Data::CryptoTransfer(
110 services::CryptoTransferTransactionBody {
111 transfers: Some(services::TransferList { account_amounts }),
112 token_transfers: Vec::new(),
113 },
114 ));
115
116 let body_bytes = body.to_proto_bytes()?;
117 let signature = client.sign_with_operator(&body_bytes);
118 let mut signed_transaction = SignedTransaction::with_body_bytes(body_bytes);
119 signed_transaction.add_signature_pair(client.to_signature_pair_protobuf(&signature))?;
120 let signed_transaction_bytes = signed_transaction.to_proto_bytes()?;
121
122 #[allow(deprecated)]
123 Ok(services::Transaction {
124 body: None,
125 sigs: None,
126 body_bytes: Vec::new(),
127 sig_map: None,
128 signed_transaction_bytes,
129 })
130}
131
132#[derive(Debug, Clone, PartialEq)]
133pub struct Query {
134 pub services: services::Query,
135
136 pub payment_transaction_id: Option<TransactionId>,
137 pub payment_transactions: Vec<services::Transaction>,
138 pub node_account_ids: Vec<AccountId>,
139
140 pub query_payment: Hbar,
141 pub max_query_payment: Hbar,
142 pub next_payment_transaction_index: usize,
143 pub next_transaction_index: usize,
144 pub max_retry: u8,
145 pub min_backoff: Option<u64>,
146 pub max_backoff: Option<u64>,
147
148 pub is_payment_required: bool,
149}
150
151impl Query {
152 pub fn new(is_payment_required: bool) -> Query {
153 Query {
154 services: services::Query { query: None },
155 payment_transaction_id: None,
156 payment_transactions: Vec::new(),
157 node_account_ids: Vec::new(),
158 query_payment: Hbar::zero(),
159 max_query_payment: Hbar::zero(),
160 next_payment_transaction_index: 0,
161 next_transaction_index: 0,
162 max_retry: 5,
163 min_backoff: None,
164 max_backoff: None,
165 is_payment_required,
166 }
167 }
168
169 pub fn with_max_query_payment(payment: Hbar) -> Query {
170 let mut query = Query::new(true);
171 query.max_query_payment = payment;
172 query
173 }
174
175 pub fn generate_payments_for_node_account_ids(
176 &mut self,
177 client: &Client,
178 cost: Hbar,
179 ) -> Result<(), HederaError> {
180 let transaction_id = match &self.payment_transaction_id {
181 Some(v) => v,
182 None => {
183 return Err(HederaError::ValueNotSet(
184 "payment_transaction_id".to_string(),
185 ))
186 }
187 };
188 for node_id in self.node_account_ids.iter() {
189 let transaction = query_make_payment_transaction(
190 Some(transaction_id.clone()),
191 Some(node_id.clone()),
192 &client,
193 Some(cost),
194 )?;
195 self.payment_transactions.push(transaction);
196 }
197 Ok(())
198 }
199}