iota_sdk/apis/
quorum_driver.rs1use std::{
6 sync::Arc,
7 time::{Duration, Instant},
8};
9
10use iota_json_rpc_api::{ReadApiClient, WriteApiClient};
11use iota_json_rpc_types::{IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions};
12use iota_types::{
13 quorum_driver_types::ExecuteTransactionRequestType, transaction::TransactionEnvelope,
14};
15
16use crate::{
17 RpcClient,
18 error::{Error, IotaRpcResult},
19};
20
21const WAIT_FOR_LOCAL_EXECUTION_MIN_INTERVAL: Duration = Duration::from_millis(100);
22const WAIT_FOR_LOCAL_EXECUTION_MAX_INTERVAL: Duration = Duration::from_secs(2);
23
24#[derive(Clone)]
26pub struct QuorumDriverApi {
27 api: Arc<RpcClient>,
28}
29
30impl QuorumDriverApi {
31 pub(crate) fn new(api: Arc<RpcClient>) -> Self {
32 Self { api }
33 }
34
35 pub async fn execute_transaction_block(
44 &self,
45 tx: TransactionEnvelope,
46 options: IotaTransactionBlockResponseOptions,
47 request_type: impl Into<Option<ExecuteTransactionRequestType>>,
48 ) -> IotaRpcResult<IotaTransactionBlockResponse> {
49 let (tx_bytes, signatures) = tx.to_tx_bytes_and_signatures();
50 let request_type = request_type
51 .into()
52 .unwrap_or_else(|| options.default_execution_request_type());
53
54 let start = Instant::now();
55 let response = self
56 .api
57 .http
58 .execute_transaction_block(
59 tx_bytes.clone(),
60 signatures.clone(),
61 Some(options.clone()),
62 None,
65 )
66 .await?;
67
68 if let ExecuteTransactionRequestType::WaitForEffectsCert = request_type {
69 return Ok(response);
70 }
71
72 let wait_for_local_execution_timeout: Duration = if cfg!(msim) {
75 Duration::from_secs(120)
77 } else {
78 Duration::from_secs(60)
79 };
80 let mut poll_response = tokio::time::timeout(wait_for_local_execution_timeout, async {
81 let mut backoff = iota_common::backoff::ExponentialBackoff::new(
82 WAIT_FOR_LOCAL_EXECUTION_MIN_INTERVAL,
83 WAIT_FOR_LOCAL_EXECUTION_MAX_INTERVAL,
84 );
85 loop {
86 tokio::time::sleep(backoff.next().unwrap()).await;
91
92 if let Ok(poll_response) = self
93 .api
94 .http
95 .get_transaction_block(*tx.digest(), Some(options.clone()))
96 .await
97 {
98 break poll_response;
99 }
100 }
101 })
102 .await
103 .map_err(|_| {
104 Error::FailToConfirmTransactionStatus(*tx.digest(), start.elapsed().as_secs())
105 })?;
106
107 poll_response.confirmed_local_execution = Some(true);
108 Ok(poll_response)
109 }
110}