Skip to content

Commit

Permalink
feat(sdk): add TxProgressExt trait (#425)
Browse files Browse the repository at this point in the history
  • Loading branch information
shekohex authored Nov 1, 2024
1 parent ee6addc commit 2efdcc6
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 9 deletions.
Submodule forge-std updated 1 files
+1 −1 package.json
2 changes: 1 addition & 1 deletion blueprints/incredible-squaring/contracts/lib/forge-std
Submodule forge-std updated 1 files
+1 −1 package.json
5 changes: 5 additions & 0 deletions cli/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub use alloy_signer_local::PrivateKeySigner;
use color_eyre::eyre::{self, Context, ContextCompat, OptionExt, Result};
use gadget_blueprint_proc_macro_core::{BlueprintManager, ServiceBlueprint};
use gadget_sdk::clients::tangle::runtime::TangleConfig;
#[cfg(test)]
use gadget_sdk::tx::tangle::TxProgressExt;
pub use k256;
use std::fmt::Debug;
use std::path::PathBuf;
Expand Down Expand Up @@ -95,6 +97,9 @@ pub async fn deploy_to_tangle(
.tx()
.sign_and_submit_then_watch_default(&create_blueprint_tx, &signer)
.await?;
#[cfg(test)]
let result = progress.wait_for_in_block_success().await?;
#[cfg(not(test))]
let result = progress.wait_for_finalized_success().await?;
let event = result
.find::<TangleApi::services::events::BlueprintCreated>()
Expand Down
105 changes: 98 additions & 7 deletions sdk/src/tx/tangle.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,80 @@
use subxt::{
client::OnlineClientT,
error::TransactionError,
tx::{TxInBlock, TxStatus},
};

use crate::debug;

/// Extension trait for transaction progress handling.
///
/// This trait provides additional methods for handling the progress of a transaction,
/// such as waiting for the transaction to be included in a block successfully.
///
/// # Type Parameters
///
/// - `T`: The configuration type for the Substrate runtime.
/// - `C`: The client type that implements the `OnlineClientT` trait.
#[async_trait::async_trait]
pub trait TxProgressExt<T: subxt::Config, C> {
/// Wait for the transaction to be in block, and return a [`TxInBlock`]
/// instance when it is, or an error if there was a problem waiting for finalization.
///
/// **Note:** consumes `self`. If you'd like to perform multiple actions as the state of the
/// transaction progresses, use [`TxProgress::next()`] instead.
///
/// **Note:** transaction statuses like `Invalid`/`Usurped`/`Dropped` indicate with some
/// probability that the transaction will not make it into a block but there is no guarantee
/// that this is true. In those cases the stream is closed however, so you currently have no way to find
/// out if they finally made it into a block or not.
async fn wait_for_in_block(mut self) -> Result<TxInBlock<T, C>, subxt::Error>;

/// Wait for the transaction to be finalized, and for the transaction events to indicate
/// that the transaction was successful. Returns the events associated with the transaction,
/// as well as a couple of other details (block hash and extrinsic hash).
///
/// **Note:** consumes self. If you'd like to perform multiple actions as progress is made,
/// use [`TxProgress::next()`] instead.
///
/// **Note:** transaction statuses like `Invalid`/`Usurped`/`Dropped` indicate with some
/// probability that the transaction will not make it into a block but there is no guarantee
/// that this is true. In those cases the stream is closed however, so you currently have no way to find
/// out if they finally made it into a block or not.
async fn wait_for_in_block_success(
self,
) -> Result<subxt::blocks::ExtrinsicEvents<T>, subxt::Error>;
}

#[async_trait::async_trait]
impl<T: subxt::Config, C: OnlineClientT<T>> TxProgressExt<T, C> for subxt::tx::TxProgress<T, C> {
async fn wait_for_in_block(mut self) -> Result<TxInBlock<T, C>, subxt::Error> {
while let Some(status) = self.next().await {
match status? {
// In Block! Return.
TxStatus::InBestBlock(s) => return Ok(s),
// Error scenarios; return the error.
TxStatus::Error { message } => return Err(TransactionError::Error(message).into()),
TxStatus::Invalid { message } => {
return Err(TransactionError::Invalid(message).into())
}
TxStatus::Dropped { message } => {
return Err(TransactionError::Dropped(message).into())
}
// Ignore and wait for next status event:
_ => continue,
}
}
Err(subxt::error::RpcError::SubscriptionDropped.into())
}

async fn wait_for_in_block_success(
self,
) -> Result<subxt::blocks::ExtrinsicEvents<T>, subxt::Error> {
let evs = self.wait_for_in_block().await?.wait_for_success().await?;
Ok(evs)
}
}

/// Send a transaction to the Tangle network.
///
/// # Errors
Expand Down Expand Up @@ -27,11 +102,27 @@ where
.sign_and_submit_then_watch_default(xt, signer)
.await?;

debug!("Waiting for finalized success ...");
let result = progress.wait_for_finalized_success().await?;
debug!(
"Transaction with hash: {:?} has been finalized",
result.extrinsic_hash()
);
Ok(result)
#[cfg(not(test))]
{
debug!("Waiting for finalized success ...");
let result = progress.wait_for_finalized_success().await?;
debug!(
"Transaction with hash: {:?} has been finalized",
result.extrinsic_hash()
);
Ok(result)
}
#[cfg(test)]
{
// In tests, we don't wait for the transaction to be finalized.
// This is because the test environment we will be using instant sealing.
// Instead, we just wait for the transaction to be included in a block.
debug!("Waiting for in block success ...");
let result = progress.wait_for_in_block_success().await?;
debug!(
"Transaction with hash: {:?} has been included in a block",
result.extrinsic_hash()
);
Ok(result)
}
}

0 comments on commit 2efdcc6

Please sign in to comment.