hedera_rust_client/
query.rs

1use 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}