use crate::{
types::{
api::core::dto::LedgerInclusionStateDto,
block::{
payload::{transaction::TransactionId, Payload},
Block, BlockId,
},
},
wallet::account::{types::InclusionState, Account},
};
const DEFAULT_RETRY_UNTIL_INCLUDED_INTERVAL: u64 = 1;
const DEFAULT_RETRY_UNTIL_INCLUDED_MAX_AMOUNT: u64 = 40;
impl Account {
pub async fn retry_until_included(
&self,
block_id: &BlockId,
interval: Option<u64>,
max_attempts: Option<u64>,
) -> crate::wallet::Result<Vec<(BlockId, Block)>> {
Ok(self
.client
.retry_until_included(block_id, interval, max_attempts)
.await?)
}
pub async fn retry_transaction_until_included(
&self,
transaction_id: &TransactionId,
interval: Option<u64>,
max_attempts: Option<u64>,
) -> crate::wallet::Result<BlockId> {
log::debug!("[retry_transaction_until_included]");
let transaction = self.read().await.transactions.get(transaction_id).cloned();
if let Some(transaction) = transaction {
if transaction.inclusion_state == InclusionState::Confirmed {
return transaction
.block_id
.ok_or(crate::wallet::Error::MissingParameter("block id"));
}
if transaction.inclusion_state == InclusionState::Conflicting
|| transaction.inclusion_state == InclusionState::UnknownPruned
{
return Err(crate::client::Error::TangleInclusion(format!(
"transaction id: {} inclusion state: {:?}",
transaction_id, transaction.inclusion_state
))
.into());
}
let block_id = match transaction.block_id {
Some(block_id) => block_id,
None => self
.client
.block()
.finish_block(Some(Payload::Transaction(Box::new(transaction.payload.clone()))))
.await?
.id(),
};
let mut block_ids = vec![block_id];
for _ in 0..max_attempts.unwrap_or(DEFAULT_RETRY_UNTIL_INCLUDED_MAX_AMOUNT) {
let duration =
std::time::Duration::from_secs(interval.unwrap_or(DEFAULT_RETRY_UNTIL_INCLUDED_INTERVAL));
#[cfg(target_family = "wasm")]
gloo_timers::future::TimeoutFuture::new(duration.as_millis() as u32).await;
#[cfg(not(target_family = "wasm"))]
tokio::time::sleep(duration).await;
let block_ids_len = block_ids.len();
let mut conflicting = false;
for (index, block_id_) in block_ids.clone().iter().enumerate() {
let block_metadata = self.client.get_block_metadata(block_id_).await?;
if let Some(inclusion_state) = block_metadata.ledger_inclusion_state {
match inclusion_state {
LedgerInclusionStateDto::Included | LedgerInclusionStateDto::NoTransaction => {
return Ok(*block_id_);
}
LedgerInclusionStateDto::Conflicting => conflicting = true,
};
}
if index == block_ids_len - 1 {
if block_metadata.should_promote.unwrap_or(false) {
self.client.promote_unchecked(block_ids.last().unwrap()).await?;
} else if block_metadata.should_reattach.unwrap_or(false) {
let reattached_block = self
.client
.block()
.finish_block(Some(Payload::Transaction(Box::new(transaction.payload.clone()))))
.await?;
block_ids.push(reattached_block.id());
}
}
}
if conflicting {
let included_block = self.client.get_included_block(transaction_id).await?;
return Ok(included_block.id());
}
}
Err(crate::client::Error::TangleInclusion(block_id.to_string()).into())
} else {
Err(crate::wallet::Error::TransactionNotFound(*transaction_id))
}
}
}