Skip to content

Commit

Permalink
refactor: use TxStatus to map revert errors
Browse files Browse the repository at this point in the history
  • Loading branch information
hal3e committed Sep 27, 2023
1 parent 337d0ea commit 96dc930
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 95 deletions.
41 changes: 18 additions & 23 deletions packages/fuels-accounts/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,32 +282,27 @@ impl Provider {
Ok(self.client.node_info().await?.into())
}

pub async fn checked_dry_run<T: Transaction>(&self, tx: T) -> Result<Vec<Receipt>> {
pub async fn checked_dry_run<T: Transaction>(&self, tx: T) -> Result<TxStatus> {
let receipts = self.dry_run(tx).await?;
Self::has_script_succeeded(&receipts)?;

Ok(receipts)
Ok(Self::tx_status_from_receipts(receipts))
}

fn has_script_succeeded(receipts: &[Receipt]) -> Result<()> {
receipts
.iter()
.find_map(|receipt| match receipt {
Receipt::ScriptResult { result, .. }
if *result != ScriptExecutionResult::Success =>
{
Some(format!("{result:?}"))
}
_ => None,
})
.map(|error_message| {
Err(Error::RevertTransactionError {
reason: error_message,
revert_id: 0,
receipts: receipts.to_owned(),
})
})
.unwrap_or(Ok(()))
fn tx_status_from_receipts(receipts: Vec<Receipt>) -> TxStatus {
let revert_reason = receipts.iter().find_map(|receipt| match receipt {
Receipt::ScriptResult { result, .. } if *result != ScriptExecutionResult::Success => {
Some(format!("{result:?}"))
}
_ => None,
});

match revert_reason {
Some(reason) => TxStatus::Revert {
receipts,
reason,
id: 0,
},
None => TxStatus::Success { receipts },
}
}

pub async fn dry_run<T: Transaction>(&self, tx: T) -> Result<Vec<Receipt>> {
Expand Down
36 changes: 0 additions & 36 deletions packages/fuels-core/src/codec/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ use std::{
iter::FilterMap,
};

use fuel_abi_types::error_codes::{
FAILED_ASSERT_EQ_SIGNAL, FAILED_ASSERT_SIGNAL, FAILED_REQUIRE_SIGNAL,
FAILED_SEND_MESSAGE_SIGNAL, FAILED_TRANSFER_TO_ADDRESS_SIGNAL,
};
use fuel_tx::{ContractId, Receipt};

use crate::{
Expand Down Expand Up @@ -208,38 +204,6 @@ impl<'a, I: Iterator<Item = &'a Receipt>> ExtractLogIdData for I {
}
}

/// Map the provided `RevertTransactionError` based on the `revert_id`.
/// If applicable, decode the logged types from the receipt.
pub fn map_revert_error(mut err: Error, log_decoder: &LogDecoder) -> Error {
if let Error::RevertTransactionError {
revert_id,
ref receipts,
ref mut reason,
} = err
{
match revert_id {
FAILED_REQUIRE_SIGNAL => {
*reason = log_decoder.decode_last_log(receipts).unwrap_or_else(|err| {
format!("failed to decode log from require revert: {err}")
})
}
FAILED_ASSERT_EQ_SIGNAL => {
*reason = match log_decoder.decode_last_two_logs(receipts) {
Ok((lhs, rhs)) => format!(
"assertion failed: `(left == right)`\n left: `{lhs:?}`\n right: `{rhs:?}`"
),
Err(err) => format!("failed to decode log from assert_eq revert: {err}"),
};
}
FAILED_ASSERT_SIGNAL => *reason = "assertion failed.".into(),
FAILED_SEND_MESSAGE_SIGNAL => *reason = "failed to send message.".into(),
FAILED_TRANSFER_TO_ADDRESS_SIGNAL => *reason = "failed transfer to address.".into(),
_ => {}
}
}
err
}

pub fn log_formatters_lookup(
log_id_log_formatter_pairs: Vec<(u64, LogFormatter)>,
contract_id: ContractId,
Expand Down
36 changes: 12 additions & 24 deletions packages/fuels-programs/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use fuel_tx::{
};
use fuels_accounts::{provider::TransactionCost, Account};
use fuels_core::{
codec::{map_revert_error, ABIEncoder, DecoderConfig, LogDecoder},
codec::{ABIEncoder, DecoderConfig, LogDecoder},
constants::{BASE_ASSET_ID, DEFAULT_CALL_PARAMS_AMOUNT},
traits::{Parameterize, Tokenizable},
types::{
Expand Down Expand Up @@ -576,9 +576,7 @@ where

/// Call a contract's method on the node, in a state-modifying manner.
pub async fn call(mut self) -> Result<FuelCallResponse<D>> {
self.call_or_simulate(false)
.await
.map_err(|err| map_revert_error(err, &self.log_decoder))
self.call_or_simulate(false).await
}

pub async fn submit(mut self) -> Result<SubmitResponse<T, D>> {
Expand Down Expand Up @@ -607,9 +605,7 @@ where
/// blockchain is *not* modified but simulated.
///
pub async fn simulate(&mut self) -> Result<FuelCallResponse<D>> {
self.call_or_simulate(true)
.await
.map_err(|err| map_revert_error(err, &self.log_decoder))
self.call_or_simulate(true).await
}

async fn call_or_simulate(&mut self, simulate: bool) -> Result<FuelCallResponse<D>> {
Expand All @@ -618,15 +614,13 @@ where

self.cached_tx_id = Some(tx.id(provider.chain_id()));

let receipts = if simulate {
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?
.take_receipts_checked(Some(&self.log_decoder))?
provider.tx_status(&tx_id).await?
};
let receipts = tx_status.take_receipts_checked(Some(&self.log_decoder))?;

self.get_response(receipts)
}
Expand Down Expand Up @@ -864,9 +858,7 @@ impl<T: Account> MultiContractCallHandler<T> {

/// Call contract methods on the node, in a state-modifying manner.
pub async fn call<D: Tokenizable + Debug>(&mut self) -> Result<FuelCallResponse<D>> {
self.call_or_simulate(false)
.await
.map_err(|err| map_revert_error(err, &self.log_decoder))
self.call_or_simulate(false).await
}

pub async fn submit(mut self) -> Result<SubmitResponseMultiple<T>> {
Expand Down Expand Up @@ -897,9 +889,7 @@ impl<T: Account> MultiContractCallHandler<T> {
///
/// [call]: Self::call
pub async fn simulate<D: Tokenizable + Debug>(&mut self) -> Result<FuelCallResponse<D>> {
self.call_or_simulate(true)
.await
.map_err(|err| map_revert_error(err, &self.log_decoder))
self.call_or_simulate(true).await
}

async fn call_or_simulate<D: Tokenizable + Debug>(
Expand All @@ -911,15 +901,13 @@ impl<T: Account> MultiContractCallHandler<T> {

self.cached_tx_id = Some(tx.id(provider.chain_id()));

let receipts = if simulate {
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?
.take_receipts_checked(Some(&self.log_decoder))?
provider.tx_status(&tx_id).await?
};
let receipts = tx_status.take_receipts_checked(Some(&self.log_decoder))?;

self.get_response(receipts)
}
Expand All @@ -929,7 +917,7 @@ impl<T: Account> MultiContractCallHandler<T> {
let provider = self.account.try_provider()?;
let tx = self.build_tx().await?;

provider.checked_dry_run(tx).await?;
provider.checked_dry_run(tx).await?.check(None)?;

Ok(())
}
Expand Down
18 changes: 6 additions & 12 deletions packages/fuels-programs/src/script_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use fuels_accounts::{
Account,
};
use fuels_core::{
codec::{map_revert_error, DecoderConfig, LogDecoder},
codec::{DecoderConfig, LogDecoder},
constants::BASE_ASSET_ID,
offsets::base_offset_script,
traits::{Parameterize, Tokenizable},
Expand Down Expand Up @@ -234,24 +234,20 @@ where
let tx = self.build_tx().await?;
self.cached_tx_id = Some(tx.id(self.provider.chain_id()));

let receipts = if simulate {
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?
.take_receipts_checked(Some(&self.log_decoder))?
self.provider.tx_status(&tx_id).await?
};
let receipts = tx_status.take_receipts_checked(Some(&self.log_decoder))?;

self.get_response(receipts)
}

/// Call a script on the node, in a state-modifying manner.
pub async fn call(mut self) -> Result<FuelCallResponse<D>> {
self.call_or_simulate(false)
.await
.map_err(|err| map_revert_error(err, &self.log_decoder))
self.call_or_simulate(false).await
}

pub async fn submit(mut self) -> Result<SubmitResponse<T, D>> {
Expand Down Expand Up @@ -280,9 +276,7 @@ where
///
/// [`call`]: Self::call
pub async fn simulate(&mut self) -> Result<FuelCallResponse<D>> {
self.call_or_simulate(true)
.await
.map_err(|err| map_revert_error(err, &self.log_decoder))
self.call_or_simulate(true).await
}

/// Get a scripts's estimated cost
Expand Down

0 comments on commit 96dc930

Please sign in to comment.