1use std::borrow::Cow;
4use std::collections::HashMap;
5use std::fmt;
6use std::num::{
7 NonZeroU64,
8 NonZeroUsize,
9};
10use std::sync::atomic::{
11 AtomicBool,
12 AtomicU64,
13 Ordering,
14};
15use std::time::Duration;
16
17pub(crate) use network::{
18 Network,
19 NetworkData,
20};
21pub(crate) use operator::Operator;
22use parking_lot::RwLock;
23use tokio::sync::watch;
24use triomphe::Arc;
25
26use self::network::managed::ManagedNetwork;
27use self::network::mirror::MirrorNetwork;
28pub(crate) use self::network::mirror::MirrorNetworkData;
29use crate::ping_query::PingQuery;
30use crate::signer::AnySigner;
31use crate::{
32 AccountId,
33 ArcSwapOption,
34 Error,
35 Hbar,
36 LedgerId,
37 NodeAddressBook,
38 NodeAddressBookQuery,
39 PrivateKey,
40 PublicKey,
41};
42
43#[cfg(feature = "serde")]
44mod config;
45
46mod network;
47mod operator;
48
49pub(crate) const DEFAULT_GRPC_DEADLINE: Duration = Duration::from_secs(10);
51
52pub(crate) const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(120);
54
55#[derive(Copy, Clone)]
56pub(crate) struct ClientBackoff {
57 pub(crate) max_backoff: Duration,
58 pub(crate) initial_backoff: Duration,
60 pub(crate) max_attempts: usize,
61 pub(crate) request_timeout: Option<Duration>,
62 pub(crate) grpc_deadline: Duration,
63}
64
65impl Default for ClientBackoff {
66 fn default() -> Self {
67 Self {
68 max_backoff: Duration::from_millis(backoff::default::MAX_INTERVAL_MILLIS),
69 initial_backoff: Duration::from_millis(backoff::default::INITIAL_INTERVAL_MILLIS),
70 max_attempts: 10,
71 request_timeout: Some(DEFAULT_REQUEST_TIMEOUT),
72 grpc_deadline: DEFAULT_GRPC_DEADLINE,
73 }
74 }
75}
76
77struct ClientBuilder {
79 network: ManagedNetwork,
80 operator: Option<Operator>,
81 max_transaction_fee: Option<NonZeroU64>,
82 max_query_payment: Option<NonZeroU64>,
83 ledger_id: Option<LedgerId>,
84 auto_validate_checksums: bool,
85 regenerate_transaction_ids: bool,
86 update_network: bool,
87 backoff: ClientBackoff,
88}
89
90impl ClientBuilder {
91 #[must_use]
92 fn new(network: ManagedNetwork) -> Self {
93 Self {
94 network,
95 operator: None,
96 max_transaction_fee: None,
97 max_query_payment: None,
98 ledger_id: None,
99 auto_validate_checksums: false,
100 regenerate_transaction_ids: true,
101 update_network: true,
102 backoff: ClientBackoff::default(),
103 }
104 }
105
106 fn disable_network_updating(self) -> Self {
107 Self { update_network: false, ..self }
108 }
109
110 fn ledger_id(self, ledger_id: Option<LedgerId>) -> Self {
111 Self { ledger_id, ..self }
112 }
113
114 fn build(self) -> Client {
115 let Self {
116 network,
117 operator,
118 max_transaction_fee,
119 max_query_payment,
120 ledger_id,
121 auto_validate_checksums,
122 regenerate_transaction_ids,
123 update_network,
124 backoff,
125 } = self;
126
127 let network_update_tx = match update_network {
128 true => network::managed::spawn_network_update(
129 network.clone(),
130 Some(Duration::from_secs(24 * 60 * 60)),
131 ),
132 false => watch::channel(None).0,
134 };
135
136 Client(Arc::new(ClientInner {
137 network,
138 operator: ArcSwapOption::new(operator.map(Arc::new)),
139 max_transaction_fee_tinybar: AtomicU64::new(
140 max_transaction_fee.map_or(0, NonZeroU64::get),
141 ),
142 max_query_payment_tinybar: AtomicU64::new(max_query_payment.map_or(0, NonZeroU64::get)),
143 ledger_id: ArcSwapOption::new(ledger_id.map(Arc::new)),
144 auto_validate_checksums: AtomicBool::new(auto_validate_checksums),
145 regenerate_transaction_ids: AtomicBool::new(regenerate_transaction_ids),
146 network_update_tx,
147 backoff: RwLock::new(backoff),
148 }))
149 }
150}
151
152struct ClientInner {
153 network: ManagedNetwork,
154 operator: ArcSwapOption<Operator>,
155 max_transaction_fee_tinybar: AtomicU64,
156 max_query_payment_tinybar: AtomicU64,
157 ledger_id: ArcSwapOption<LedgerId>,
158 auto_validate_checksums: AtomicBool,
159 regenerate_transaction_ids: AtomicBool,
160 network_update_tx: watch::Sender<Option<Duration>>,
161 backoff: RwLock<ClientBackoff>,
162}
163
164#[derive(Clone)]
166pub struct Client(Arc<ClientInner>);
167
168impl fmt::Debug for Client {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 f.debug_struct("Client").finish_non_exhaustive()
172 }
173}
174
175impl Client {
176 #[cfg(feature = "serde")]
177 fn from_config_data(config: config::ClientConfig) -> crate::Result<Self> {
178 let config::ClientConfig { operator, network, mirror_network } = config;
179
180 let client = match network {
182 config::Either::Left(network) => Client::for_network(network)?,
183 config::Either::Right(it) => match it {
184 config::NetworkName::Mainnet => Client::for_mainnet(),
185 config::NetworkName::Testnet => Client::for_testnet(),
186 config::NetworkName::Previewnet => Client::for_previewnet(),
187 },
188 };
189
190 let mirror_network = mirror_network.map(|mirror_network| match mirror_network {
191 config::Either::Left(mirror_network) => {
192 MirrorNetwork::from_addresses(mirror_network.into_iter().map(Cow::Owned).collect())
193 }
194 config::Either::Right(it) => match it {
195 config::NetworkName::Mainnet => MirrorNetwork::mainnet(),
196 config::NetworkName::Testnet => MirrorNetwork::testnet(),
197 config::NetworkName::Previewnet => MirrorNetwork::previewnet(),
198 },
199 });
200
201 if let Some(operator) = operator {
202 client.0.operator.store(Some(Arc::new(operator)));
203 }
204
205 if let Some(mirror_network) = mirror_network {
206 client.set_mirror_network(mirror_network.load().addresses());
207 }
208
209 Ok(client)
210 }
211
212 #[cfg(feature = "serde")]
217 pub fn from_config(json: &str) -> crate::Result<Self> {
218 let config = serde_json::from_str::<config::ClientConfigInner>(json)
219 .map_err(crate::Error::basic_parse)?
220 .into();
221
222 Self::from_config_data(config)
223 }
224
225 #[must_use]
252 pub fn mirror_network(&self) -> Vec<String> {
253 self.mirrornet().load().addresses().collect()
254 }
255
256 pub fn set_mirror_network<I: IntoIterator<Item = String>>(&self, addresses: I) {
260 self.mirrornet().store(
261 MirrorNetworkData::from_addresses(addresses.into_iter().map(Cow::Owned).collect())
262 .into(),
263 );
264 }
265
266 #[allow(clippy::needless_pass_by_value)]
274 pub fn for_network(network: HashMap<String, AccountId>) -> crate::Result<Self> {
275 let network =
276 ManagedNetwork::new(Network::from_addresses(&network)?, MirrorNetwork::default());
277
278 Ok(ClientBuilder::new(network).disable_network_updating().build())
279 }
280
281 pub async fn for_mirror_network(mirror_networks: Vec<String>) -> crate::Result<Self> {
283 Self::for_mirror_network_with_shard_realm(mirror_networks, 0, 0).await
284 }
285
286 pub async fn for_mirror_network_with_shard_realm(
288 mirror_networks: Vec<String>,
289 shard: u64,
290 realm: u64,
291 ) -> crate::Result<Self> {
292 let network_addresses: HashMap<String, AccountId> = HashMap::new();
293 let network = ManagedNetwork::new(
294 Network::from_addresses(&network_addresses)?,
295 MirrorNetwork::from_addresses(mirror_networks.into_iter().map(Cow::Owned).collect()),
296 );
297
298 let client = ClientBuilder::new(network).build();
299 let address_book = if shard == 0 && realm == 0 {
300 NodeAddressBookQuery::default().execute(&client).await?
301 } else {
302 NodeAddressBookQuery::new().shard(shard).realm(realm).execute(&client).await?
303 };
304
305 client.set_network_from_address_book(address_book);
306
307 Ok(client)
308 }
309
310 #[must_use]
312 pub fn for_mainnet() -> Self {
313 ClientBuilder::new(ManagedNetwork::mainnet()).ledger_id(Some(LedgerId::mainnet())).build()
314 }
315
316 #[must_use]
318 pub fn for_testnet() -> Self {
319 ClientBuilder::new(ManagedNetwork::testnet()).ledger_id(Some(LedgerId::testnet())).build()
320 }
321
322 #[must_use]
324 pub fn for_previewnet() -> Self {
325 ClientBuilder::new(ManagedNetwork::previewnet())
326 .ledger_id(Some(LedgerId::previewnet()))
327 .build()
328 }
329
330 #[allow(clippy::needless_pass_by_value)]
337 pub fn set_network_from_address_book(&self, address_book: NodeAddressBook) {
338 self.net().update_from_address_book(&address_book);
339 }
340
341 #[allow(clippy::needless_pass_by_value)]
353 pub fn set_network(&self, network: HashMap<String, AccountId>) -> crate::Result<()> {
354 self.net().update_from_addresses(&network)?;
355
356 Ok(())
357 }
358
359 #[must_use]
361 pub fn network(&self) -> HashMap<String, AccountId> {
362 self.net().0.load().addresses()
363 }
364
365 pub fn max_node_attempts(&self) -> Option<NonZeroUsize> {
367 self.net().0.load().max_node_attempts()
368 }
369
370 pub fn set_max_node_attempts(&self, attempts: usize) {
372 self.net().0.load().set_max_node_attempts(NonZeroUsize::new(attempts))
373 }
374
375 pub fn max_node_backoff(&self) -> Duration {
377 self.net().0.load().max_backoff()
378 }
379
380 pub fn set_max_node_backoff(&self, max_node_backoff: Duration) {
382 self.net().0.load().set_max_backoff(max_node_backoff)
383 }
384
385 pub fn min_node_backoff(&self) -> Duration {
387 self.net().0.load().min_backoff()
388 }
389
390 pub fn set_min_node_backoff(&self, min_node_backoff: Duration) {
392 self.net().0.load().set_min_backoff(min_node_backoff)
393 }
394
395 pub fn for_name(name: &str) -> crate::Result<Self> {
402 match name {
403 "mainnet" => Ok(Self::for_mainnet()),
404 "testnet" => Ok(Self::for_testnet()),
405 "previewnet" => Ok(Self::for_previewnet()),
406 "localhost" => {
407 let mut network: HashMap<String, AccountId> = HashMap::new();
408 network.insert("127.0.0.1:50211".to_string(), AccountId::new(0, 0, 3));
409
410 let client = Client::for_network(network).unwrap();
411 client.set_mirror_network(["127.0.0.1:5600".to_string()]);
412 Ok(client)
413 }
414 _ => Err(Error::basic_parse(format!("Unknown network name {name}"))),
415 }
416 }
417
418 pub(crate) fn ledger_id_internal(&self) -> arc_swap::Guard<Option<Arc<LedgerId>>> {
421 self.0.ledger_id.load()
422 }
423
424 pub fn set_ledger_id(&self, ledger_id: Option<LedgerId>) {
426 self.0.ledger_id.store(ledger_id.map(Arc::new));
427 }
428
429 #[must_use]
431 pub fn auto_validate_checksums(&self) -> bool {
432 self.0.auto_validate_checksums.load(Ordering::Relaxed)
433 }
434
435 pub fn set_auto_validate_checksums(&self, value: bool) {
437 self.0.auto_validate_checksums.store(value, Ordering::Relaxed);
438 }
439
440 #[must_use]
444 pub fn default_regenerate_transaction_id(&self) -> bool {
445 self.0.regenerate_transaction_ids.load(Ordering::Relaxed)
446 }
447
448 pub fn set_default_regenerate_transaction_id(&self, value: bool) {
450 self.0.regenerate_transaction_ids.store(value, Ordering::Relaxed);
451 }
452
453 pub fn set_operator(&self, id: AccountId, key: PrivateKey) {
461 self.0
462 .operator
463 .store(Some(Arc::new(Operator { account_id: id, signer: AnySigner::PrivateKey(key) })));
464 }
465
466 pub fn set_operator_with<F: Fn(&[u8]) -> Vec<u8> + Send + Sync + 'static>(
474 &self,
475 id: AccountId,
476 public_key: PublicKey,
477 f: F,
478 ) {
479 self.0.operator.store(Some(Arc::new(Operator {
480 account_id: id,
481 signer: AnySigner::arbitrary(Box::new(public_key), f),
482 })));
483 }
484
485 pub(crate) fn net(&self) -> &Network {
487 &self.0.network.primary
488 }
489
490 pub(crate) fn mirrornet(&self) -> &MirrorNetwork {
492 &self.0.network.mirror
493 }
494
495 pub fn set_default_max_transaction_fee(&self, amount: Hbar) {
501 assert!(amount >= Hbar::ZERO);
502 self.0.max_transaction_fee_tinybar.store(amount.to_tinybars() as u64, Ordering::Relaxed);
503 }
504
505 #[must_use]
507 pub fn default_max_transaction_fee(&self) -> Option<Hbar> {
508 let val = self.0.max_transaction_fee_tinybar.load(Ordering::Relaxed);
509
510 (val > 0).then(|| Hbar::from_tinybars(val as i64))
511 }
512
513 #[must_use]
515 pub fn default_max_query_payment(&self) -> Option<Hbar> {
516 let val = self.0.max_query_payment_tinybar.load(Ordering::Relaxed);
517
518 (val > 0).then(|| Hbar::from_tinybars(val as i64))
519 }
520
521 pub fn set_default_max_query_payment(&self, amount: Hbar) {
527 assert!(amount >= Hbar::ZERO);
528 self.0.max_query_payment_tinybar.store(amount.to_tinybars() as u64, Ordering::Relaxed);
529 }
530
531 #[must_use]
533 pub fn request_timeout(&self) -> Option<Duration> {
534 self.backoff().request_timeout
535 }
536
537 pub fn set_request_timeout(&self, timeout: Option<Duration>) {
539 self.0.backoff.write().request_timeout = timeout;
540 }
541
542 #[must_use]
544 pub fn max_attempts(&self) -> usize {
545 self.backoff().max_attempts
546 }
547
548 pub fn set_max_attempts(&self, max_attempts: usize) {
550 self.0.backoff.write().max_attempts = max_attempts;
551 }
552
553 #[doc(alias = "initial_backoff")]
555 #[must_use]
556 pub fn min_backoff(&self) -> Duration {
557 self.backoff().initial_backoff
558 }
559
560 #[doc(alias = "set_initial_backoff")]
562 pub fn set_min_backoff(&self, max_backoff: Duration) {
563 self.0.backoff.write().max_backoff = max_backoff;
564 }
565
566 #[must_use]
568 pub fn max_backoff(&self) -> Duration {
569 self.backoff().max_backoff
570 }
571
572 pub fn set_max_backoff(&self, max_backoff: Duration) {
574 self.0.backoff.write().max_backoff = max_backoff;
575 }
576
577 #[must_use]
579 pub fn grpc_deadline(&self) -> Duration {
580 self.backoff().grpc_deadline
581 }
582
583 pub fn set_grpc_deadline(&self, grpc_deadline: Duration) {
587 self.0.backoff.write().grpc_deadline = grpc_deadline;
588 }
589
590 #[must_use]
591 pub(crate) fn backoff(&self) -> ClientBackoff {
592 *self.0.backoff.read()
593 }
594
595 pub(crate) fn load_operator(&self) -> arc_swap::Guard<Option<Arc<Operator>>> {
597 self.0.operator.load()
598 }
599
600 pub(crate) fn full_load_operator(&self) -> Option<Arc<Operator>> {
602 self.0.operator.load_full()
603 }
604
605 pub async fn ping(&self, node_account_id: AccountId) -> crate::Result<()> {
607 PingQuery::new(node_account_id).execute(self, None).await
608 }
609
610 pub async fn ping_with_timeout(
612 &self,
613 node_account_id: AccountId,
614 timeout: Duration,
615 ) -> crate::Result<()> {
616 PingQuery::new(node_account_id).execute(self, Some(timeout)).await
617 }
618
619 pub async fn ping_all(&self) -> crate::Result<()> {
621 futures_util::future::try_join_all(
622 self.net().0.load().node_ids().iter().map(|it| self.ping(*it)),
623 )
624 .await?;
625
626 Ok(())
627 }
628
629 pub async fn ping_all_with_timeout(&self, timeout: Duration) -> crate::Result<()> {
631 futures_util::future::try_join_all(
632 self.net().0.load().node_ids().iter().map(|it| self.ping_with_timeout(*it, timeout)),
633 )
634 .await?;
635
636 Ok(())
637 }
638
639 #[must_use = "this function has no side-effects"]
641 pub fn network_update_period(&self) -> Option<Duration> {
642 *self.0.network_update_tx.borrow()
643 }
644
645 pub fn set_network_update_period(&self, period: Option<Duration>) {
649 self.0.network_update_tx.send_if_modified(|place| {
650 let changed = *place == period;
651 if changed {
652 *place = period;
653 }
654
655 changed
656 });
657 }
658
659 pub(crate) async fn refresh_network(&self) {
662 match NodeAddressBookQuery::new()
663 .execute_mirrornet(self.mirrornet().load().channel(self.grpc_deadline()), None)
664 .await
665 {
666 Ok(address_book) => {
667 log::info!("Successfully updated network address book");
668 self.set_network_from_address_book(address_book);
669 }
670 Err(e) => {
671 log::warn!("Failed to update network address book: {e:?}");
672 }
673 }
674 }
675
676 #[must_use]
678 pub fn get_operator_account_id(&self) -> Option<AccountId> {
679 self.load_operator().as_deref().map(|it| it.account_id)
680 }
681
682 #[must_use]
684 pub fn get_operator_public_key(&self) -> Option<PublicKey> {
685 self.load_operator().as_deref().map(|it| it.signer.public_key())
686 }
687}