Skip to content

Commit

Permalink
refactor!: use submit_and_await_commit API (#1187)
Browse files Browse the repository at this point in the history
Closes #1180,  #1128.
This PR uses the correct API for sending a transaction and ensuring that
we wait for the commit of the transaction before returning.
This is needed because otherwise there might be a disconnect between
submitting the transaction and awaiting for its commit, if it is done
using the two separate APIs as before.

BREAKING CHANGE: 
- `send_transaction_and_await_commit` function now returns a `TxStatus`
instead of `TxId`.

---------

Co-authored-by: MujkicA <[email protected]>
Co-authored-by: hal3e <[email protected]>
  • Loading branch information
3 people authored Jan 8, 2024
1 parent 6959712 commit 638a548
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 44 deletions.
28 changes: 12 additions & 16 deletions packages/fuels-accounts/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use fuels_core::{
errors::{Error, Result},
input::Input,
message::Message,
transaction::TxPolicies,
transaction::{Transaction, TxPolicies},
transaction_builders::{
BuildableTransaction, ScriptTransactionBuilder, TransactionBuilder,
},
Expand Down Expand Up @@ -219,12 +219,11 @@ pub trait Account: ViewOnlyAccount {
.await?;

let tx = tx_builder.build(provider).await?;
let tx_id = provider.send_transaction_and_await_commit(tx).await?;
let tx_id = tx.id(provider.chain_id());

let receipts = provider
.tx_status(&tx_id)
.await?
.take_receipts_checked(None)?;
let tx_status = provider.send_transaction_and_await_commit(tx).await?;

let receipts = tx_status.take_receipts_checked(None)?;

Ok((tx_id, receipts))
}
Expand Down Expand Up @@ -279,12 +278,10 @@ pub trait Account: ViewOnlyAccount {
self.adjust_for_fee(&mut tb, balance).await?;
let tx = tb.build(provider).await?;

let tx_id = provider.send_transaction_and_await_commit(tx).await?;
let tx_id = tx.id(provider.chain_id());
let tx_status = provider.send_transaction_and_await_commit(tx).await?;

let receipts = provider
.tx_status(&tx_id)
.await?
.take_receipts_checked(None)?;
let receipts = tx_status.take_receipts_checked(None)?;

Ok((tx_id.to_string(), receipts))
}
Expand Down Expand Up @@ -314,12 +311,11 @@ pub trait Account: ViewOnlyAccount {
self.add_witnessses(&mut tb);
self.adjust_for_fee(&mut tb, amount).await?;
let tx = tb.build(provider).await?;
let tx_id = provider.send_transaction_and_await_commit(tx).await?;

let receipts = provider
.tx_status(&tx_id)
.await?
.take_receipts_checked(None)?;
let tx_id = tx.id(provider.chain_id());
let tx_status = provider.send_transaction_and_await_commit(tx).await?;

let receipts = tx_status.take_receipts_checked(None)?;

let nonce = extract_message_nonce(&receipts)
.expect("MessageId could not be retrieved from tx receipts.");
Expand Down
39 changes: 25 additions & 14 deletions packages/fuels-accounts/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ mod supported_versions;
use std::sync::Arc;

use chrono::{DateTime, Utc};
#[cfg(feature = "coin-cache")]
use fuel_core_client::client::types::TransactionStatus;
use fuel_core_client::client::{
pagination::{PageDirection, PaginatedResult, PaginationRequest},
types::{balance::Balance, contract::ContractBalance},
Expand Down Expand Up @@ -197,24 +195,29 @@ impl Provider {
}

/// Sends a transaction to the underlying Provider's client.
pub async fn send_transaction_and_await_commit<T: Transaction>(&self, tx: T) -> Result<TxId> {
let tx_id = self.send_transaction(tx.clone()).await?;
let _status = self.client.await_transaction_commit(&tx_id).await?;
pub async fn send_transaction_and_await_commit<T: Transaction>(
&self,
mut tx: T,
) -> Result<TxStatus> {
self.prepare_transaction_for_sending(&mut tx).await?;
let tx_status = self
.client
.submit_and_await_commit(&tx.clone().into())
.await?
.into();

#[cfg(feature = "coin-cache")]
{
if matches!(
_status,
TransactionStatus::SqueezedOut { .. } | TransactionStatus::Failure { .. }
) {
self.cache.lock().await.remove_items(tx.used_coins())
}
if matches!(
tx_status,
TxStatus::SqueezedOut { .. } | TxStatus::Revert { .. }
) {
self.cache.lock().await.remove_items(tx.used_coins())
}

Ok(tx_id)
Ok(tx_status)
}

pub async fn send_transaction<T: Transaction>(&self, mut tx: T) -> Result<TxId> {
async fn prepare_transaction_for_sending<T: Transaction>(&self, tx: &mut T) -> Result<()> {
tx.precompute(&self.chain_id())?;

let chain_info = self.chain_info().await?;
Expand All @@ -228,10 +231,18 @@ impl Provider {
}

self.validate_transaction(tx.clone()).await?;
Ok(())
}

pub async fn send_transaction<T: Transaction>(&self, mut tx: T) -> Result<TxId> {
self.prepare_transaction_for_sending(&mut tx).await?;
self.submit(tx).await
}

pub async fn await_transaction_commit<T: Transaction>(&self, id: TxId) -> Result<TxStatus> {
Ok(self.client.await_transaction_commit(&id).await?.into())
}

async fn validate_transaction<T: Transaction>(&self, tx: T) -> Result<()> {
let tolerance = 0.0;
let TransactionCost {
Expand Down
5 changes: 5 additions & 0 deletions packages/fuels-accounts/src/provider/retryable_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ impl RetryableClient {
.await
}

pub async fn submit_and_await_commit(&self, tx: &Transaction) -> io::Result<TransactionStatus> {
self.our_retry(|| self.client.submit_and_await_commit(tx))
.await
}

pub async fn submit(&self, tx: &Transaction) -> io::Result<types::primitives::TransactionId> {
self.our_retry(|| self.client.submit(tx)).await
}
Expand Down
12 changes: 6 additions & 6 deletions packages/fuels-programs/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,10 @@ impl Contract {

let provider = account.try_provider()?;

let tx_id = provider.send_transaction_and_await_commit(tx).await?;
provider.tx_status(&tx_id).await?.check(None)?;
provider
.send_transaction_and_await_commit(tx)
.await?
.check(None)?;

Ok(self.contract_id.into())
}
Expand Down Expand Up @@ -629,8 +631,7 @@ where
let tx_status = if simulate {
provider.checked_dry_run(tx).await?
} else {
let tx_id = provider.send_transaction_and_await_commit(tx).await?;
provider.tx_status(&tx_id).await?
provider.send_transaction_and_await_commit(tx).await?
};
let receipts = tx_status.take_receipts_checked(Some(&self.log_decoder))?;

Expand Down Expand Up @@ -935,8 +936,7 @@ impl<T: Account> MultiContractCallHandler<T> {
let tx_status = if simulate {
provider.checked_dry_run(tx).await?
} else {
let tx_id = provider.send_transaction_and_await_commit(tx).await?;
provider.tx_status(&tx_id).await?
provider.send_transaction_and_await_commit(tx).await?
};
let receipts = tx_status.take_receipts_checked(Some(&self.log_decoder))?;

Expand Down
3 changes: 1 addition & 2 deletions packages/fuels-programs/src/script_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,7 @@ where
let tx_status = if simulate {
self.provider.checked_dry_run(tx).await?
} else {
let tx_id = self.provider.send_transaction_and_await_commit(tx).await?;
self.provider.tx_status(&tx_id).await?
self.provider.send_transaction_and_await_commit(tx).await?
};
let receipts = tx_status.take_receipts_checked(Some(&self.log_decoder))?;

Expand Down
8 changes: 5 additions & 3 deletions packages/fuels/tests/predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,8 +749,10 @@ async fn predicate_transfer_non_base_asset() -> Result<()> {
wallet.adjust_for_fee(&mut tb, 0).await?;
let tx = tb.build(&provider).await?;

let tx_id = provider.send_transaction_and_await_commit(tx).await?;
provider.tx_status(&tx_id).await?.check(None)?;
provider
.send_transaction_and_await_commit(tx)
.await?
.check(None)?;

let wallet_balance = wallet.get_asset_balance(&non_base_asset_id).await?;

Expand Down Expand Up @@ -871,7 +873,7 @@ async fn tx_id_not_changed_after_adding_witnesses() -> Result<()> {
tx.append_witness(witness2.into())?;
let tx_id_after_witnesses = tx.id(provider.chain_id());

let tx_id_from_provider = provider.send_transaction_and_await_commit(tx).await?;
let tx_id_from_provider = provider.send_transaction(tx).await?;

assert_eq!(tx_id, tx_id_after_witnesses);
assert_eq!(tx_id, tx_id_from_provider);
Expand Down
6 changes: 3 additions & 3 deletions packages/fuels/tests/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,9 +909,9 @@ async fn test_cache_invalidation_on_await() -> Result<()> {
tokio::time::pause();

// tx inputs should be cached and then invalidated due to the tx failing
let tx_id = provider.send_transaction_and_await_commit(tx).await?;
let status = provider.tx_status(&tx_id).await?;
assert!(matches!(status, TxStatus::Revert { .. }));
let tx_status = provider.send_transaction_and_await_commit(tx).await?;

assert!(matches!(tx_status, TxStatus::Revert { .. }));

let coins = wallet.get_spendable_resources(BASE_ASSET_ID, 1).await?;
assert_eq!(coins.len(), 1);
Expand Down

0 comments on commit 638a548

Please sign in to comment.