diff --git a/packages/fuels-accounts/src/accounts_utils.rs b/packages/fuels-accounts/src/accounts_utils.rs index fb39660e81..6125bf7a81 100644 --- a/packages/fuels-accounts/src/accounts_utils.rs +++ b/packages/fuels-accounts/src/accounts_utils.rs @@ -1,4 +1,4 @@ -use fuel_tx::{ConsensusParameters, Output, Receipt}; +use fuel_tx::{Output, Receipt}; use fuel_types::MessageId; use fuels_core::{ constants::BASE_ASSET_ID, @@ -6,7 +6,7 @@ use fuels_core::{ bech32::Bech32Address, errors::{error, Error, Result}, input::Input, - transaction_builders::TransactionBuilder, + transaction_builders::{NetworkInfo, TransactionBuilder}, }, }; @@ -16,11 +16,11 @@ pub fn extract_message_id(receipts: &[Receipt]) -> Option { pub fn calculate_base_amount_with_fee( tb: &impl TransactionBuilder, - consensus_params: &ConsensusParameters, + network_info: &NetworkInfo, previous_base_amount: u64, ) -> Result { let transaction_fee = tb - .fee_checked_from_tx(consensus_params)? + .fee_checked_from_tx(network_info)? .ok_or(error!(InvalidData, "Error calculating TransactionFee"))?; let mut new_base_amount = transaction_fee.max_fee() + previous_base_amount; diff --git a/packages/fuels-accounts/src/predicate.rs b/packages/fuels-accounts/src/predicate.rs index 6e2e7a2097..ac8bcb653c 100644 --- a/packages/fuels-accounts/src/predicate.rs +++ b/packages/fuels-accounts/src/predicate.rs @@ -145,9 +145,9 @@ impl Account for Predicate { mut tb: Tb, previous_base_amount: u64, ) -> Result { - let consensus_parameters = self.try_provider()?.consensus_parameters(); + let network_info = self.try_provider()?.network_info().await?; let new_base_amount = - calculate_base_amount_with_fee(&tb, &consensus_parameters, previous_base_amount)?; + calculate_base_amount_with_fee(&tb, &network_info, previous_base_amount)?; let new_base_inputs = self .get_asset_inputs_for_amount(BASE_ASSET_ID, new_base_amount) diff --git a/packages/fuels-accounts/src/provider.rs b/packages/fuels-accounts/src/provider.rs index 8290afa8db..d6fc4e354f 100644 --- a/packages/fuels-accounts/src/provider.rs +++ b/packages/fuels-accounts/src/provider.rs @@ -186,7 +186,26 @@ impl Provider { Ok(tx_id) } - pub async fn send_transaction(&self, tx: T) -> Result { + pub async fn send_transaction(&self, mut tx: T) -> Result { + tx.precompute(&self.chain_id())?; + + let chain_info = self.chain_info().await?; + tx.check_without_signatures( + chain_info.latest_block.header.height, + &self.consensus_parameters(), + )?; + + if tx.is_using_predicates() { + tx.estimate_predicates(&self.consensus_parameters, &chain_info.gas_costs)?; + } + + self.validate_transaction(tx.clone()).await?; + + let tx_id = self.client.submit(&tx.into()).await?; + Ok(tx_id) + } + + async fn validate_transaction(&self, tx: T) -> Result<()> { let tolerance = 0.0; let TransactionCost { gas_used, @@ -212,14 +231,7 @@ impl Provider { )); } - let chain_info = self.chain_info().await?; - tx.check_without_signatures( - chain_info.latest_block.header.height, - &self.consensus_parameters(), - )?; - - let tx_id = self.client.submit(&tx.into()).await?; - Ok(tx_id) + Ok(()) } pub async fn tx_status(&self, tx_id: &TxId) -> ProviderResult { diff --git a/packages/fuels-accounts/src/wallet.rs b/packages/fuels-accounts/src/wallet.rs index 1c587e3f2a..6d6ff6e31b 100644 --- a/packages/fuels-accounts/src/wallet.rs +++ b/packages/fuels-accounts/src/wallet.rs @@ -264,11 +264,11 @@ impl Account for WalletUnlocked { mut tb: Tb, previous_base_amount: u64, ) -> Result { - let consensus_parameters = self.try_provider()?.consensus_parameters(); + let network_info = self.try_provider()?.network_info().await?; self.sign_transaction(&mut tb); let new_base_amount = - calculate_base_amount_with_fee(&tb, &consensus_parameters, previous_base_amount)?; + calculate_base_amount_with_fee(&tb, &network_info, previous_base_amount)?; let new_base_inputs = self .get_asset_inputs_for_amount(BASE_ASSET_ID, new_base_amount) diff --git a/packages/fuels-core/src/types/transaction_builders.rs b/packages/fuels-core/src/types/transaction_builders.rs index f501914e15..8c24899a1f 100644 --- a/packages/fuels-core/src/types/transaction_builders.rs +++ b/packages/fuels-core/src/types/transaction_builders.rs @@ -5,9 +5,8 @@ use std::collections::HashMap; use fuel_asm::{op, GTFArgs, RegId}; use fuel_crypto::{Message as CryptoMessage, SecretKey, Signature}; use fuel_tx::{ - field::Witnesses, Cacheable, ConsensusParameters, Create, Input as FuelInput, Output, Script, - StorageSlot, Transaction as FuelTransaction, TransactionFee, TxPointer, UniqueIdentifier, - Witness, + field::Witnesses, ConsensusParameters, Create, Input as FuelInput, Output, Script, StorageSlot, + Transaction as FuelTransaction, TransactionFee, TxPointer, UniqueIdentifier, Witness, }; use fuel_types::{bytes::padded_len_usize, Bytes32, ChainId, MemLayout, Salt}; use fuel_vm::gas::GasCosts; @@ -24,9 +23,7 @@ use crate::{ errors::{error, Error, Result}, input::Input, message::Message, - transaction::{ - estimate_predicates, CreateTransaction, ScriptTransaction, Transaction, TxParameters, - }, + transaction::{CreateTransaction, ScriptTransaction, Transaction, TxParameters}, unresolved_bytes::UnresolvedBytes, Address, AssetId, ContractId, }, @@ -67,7 +64,7 @@ pub trait TransactionBuilder: Send { fn build(self) -> Result; fn add_unresolved_signature(&mut self, owner: Bech32Address, secret_key: SecretKey); - fn fee_checked_from_tx(&self, params: &ConsensusParameters) -> Result>; + fn fee_checked_from_tx(&self, networ_info: &NetworkInfo) -> Result>; fn with_maturity(self, maturity: u32) -> Self; fn with_gas_price(self, gas_price: u64) -> Self; fn with_gas_limit(self, gas_limit: u64) -> Self; @@ -88,29 +85,20 @@ macro_rules! impl_tx_trait { impl TransactionBuilder for $ty { type TxType = $tx_ty; fn build(self) -> Result<$tx_ty> { - let uses_predicates = self.is_using_predicates(); - let base_offset = if uses_predicates { + let is_using_predicates = self.is_using_predicates(); + let base_offset = if is_using_predicates { self.base_offset() } else { 0 }; - let network_info = self.network_info.clone(); - let num_witnesses = self.num_witnesses()?; - let mut tx = self.resolve_fuel_tx(base_offset, num_witnesses)?; - - tx.precompute(&network_info.chain_id())?; + let tx = self.resolve_fuel_tx(base_offset, num_witnesses)?; - if uses_predicates { - estimate_predicates( - &mut tx, - &network_info.consensus_parameters, - &network_info.gas_costs, - )?; - }; - - Ok($tx_ty { tx }) + Ok($tx_ty { + tx, + is_using_predicates, + }) } fn add_unresolved_signature(&mut self, owner: Bech32Address, secret_key: SecretKey) { @@ -123,10 +111,23 @@ macro_rules! impl_tx_trait { fn fee_checked_from_tx( &self, - params: &ConsensusParameters, + network_info: &NetworkInfo, ) -> Result> { - let tx = self.clone().build()?.tx; - Ok(TransactionFee::checked_from_tx(params, &tx)) + let mut tx = self.clone().build()?; + + tx.precompute(&network_info.chain_id())?; + + if tx.is_using_predicates() { + tx.estimate_predicates( + &network_info.consensus_parameters, + &network_info.gas_costs, + )?; + }; + + Ok(TransactionFee::checked_from_tx( + &network_info.consensus_parameters, + &tx.tx, + )) } fn with_maturity(mut self, maturity: u32) -> Self { diff --git a/packages/fuels-core/src/types/wrappers/transaction.rs b/packages/fuels-core/src/types/wrappers/transaction.rs index 44d58f1de3..991fad58d8 100644 --- a/packages/fuels-core/src/types/wrappers/transaction.rs +++ b/packages/fuels-core/src/types/wrappers/transaction.rs @@ -100,14 +100,18 @@ pub trait Transaction: Into + Clone { fn witnesses(&self) -> &Vec; - /// Append witness and return the corresponding witness index - fn append_witness( + fn is_using_predicates(&self) -> bool; + + fn precompute(&mut self, chain_id: &ChainId) -> Result<()>; + + fn estimate_predicates( &mut self, - witness: Witness, - chain_id: &ChainId, consensus_parameters: &ConsensusParameters, gas_costs: &GasCosts, - ) -> Result; + ) -> Result<()>; + + /// Append witness and return the corresponding witness index + fn append_witness(&mut self, witness: Witness) -> usize; } impl From for FuelTransaction { @@ -222,20 +226,35 @@ impl Transaction for TransactionType { } } - fn append_witness( + fn is_using_predicates(&self) -> bool { + match self { + TransactionType::Script(tx) => tx.is_using_predicates(), + TransactionType::Create(tx) => tx.is_using_predicates(), + } + } + + fn precompute(&mut self, chain_id: &ChainId) -> Result<()> { + match self { + TransactionType::Script(tx) => tx.precompute(chain_id), + TransactionType::Create(tx) => tx.precompute(chain_id), + } + } + + fn estimate_predicates( &mut self, - witness: Witness, - chain_id: &ChainId, consensus_parameters: &ConsensusParameters, gas_costs: &GasCosts, - ) -> Result { + ) -> Result<()> { match self { - TransactionType::Script(tx) => { - tx.append_witness(witness, chain_id, consensus_parameters, gas_costs) - } - TransactionType::Create(tx) => { - tx.append_witness(witness, chain_id, consensus_parameters, gas_costs) - } + TransactionType::Script(tx) => tx.estimate_predicates(consensus_parameters, gas_costs), + TransactionType::Create(tx) => tx.estimate_predicates(consensus_parameters, gas_costs), + } + } + + fn append_witness(&mut self, witness: Witness) -> usize { + match self { + TransactionType::Script(tx) => tx.append_witness(witness), + TransactionType::Create(tx) => tx.append_witness(witness), } } } @@ -245,6 +264,7 @@ macro_rules! impl_tx_wrapper { #[derive(Debug, Clone)] pub struct $wrapper { pub(crate) tx: $wrapped, + pub(crate) is_using_predicates: bool, } impl From<$wrapper> for $wrapped { @@ -261,7 +281,19 @@ macro_rules! impl_tx_wrapper { impl From<$wrapped> for $wrapper { fn from(tx: $wrapped) -> Self { - $wrapper { tx } + let is_using_predicates = tx.inputs().iter().any(|input| { + matches!( + input, + Input::CoinPredicate { .. } + | Input::MessageCoinPredicate { .. } + | Input::MessageDataPredicate { .. } + ) + }); + + $wrapper { + tx, + is_using_predicates, + } } } @@ -330,20 +362,37 @@ macro_rules! impl_tx_wrapper { self.tx.witnesses() } - fn append_witness( + fn is_using_predicates(&self) -> bool { + self.is_using_predicates + } + + fn precompute(&mut self, chain_id: &ChainId) -> Result<()> { + Ok(self.tx.precompute(chain_id)?) + } + + fn estimate_predicates( &mut self, - witness: Witness, - chain_id: &ChainId, consensus_parameters: &ConsensusParameters, gas_costs: &GasCosts, - ) -> Result { + ) -> Result<()> { + let gas_price = *self.tx.gas_price(); + let gas_limit = *self.tx.gas_limit(); + *self.tx.gas_price_mut() = 0; + *self.tx.gas_limit_mut() = consensus_parameters.max_gas_per_tx; + + self.tx + .estimate_predicates(consensus_parameters, gas_costs)?; + *self.tx.gas_price_mut() = gas_price; + *self.tx.gas_limit_mut() = gas_limit; + + Ok(()) + } + + fn append_witness(&mut self, witness: Witness) -> usize { let idx = self.tx.witnesses().len(); self.tx.witnesses_mut().push(witness); - self.tx.precompute(chain_id)?; - estimate_predicates(&mut self.tx, consensus_parameters, gas_costs)?; - - Ok(idx) + idx } } }; @@ -379,23 +428,3 @@ impl ScriptTransaction { self.tx.script_data() } } - -pub(crate) fn estimate_predicates( - tx: &mut T, - consensus_parameters: &ConsensusParameters, - gas_costs: &GasCosts, -) -> Result<()> -where - T: GasLimit + GasPrice + EstimatePredicates, -{ - let gas_price = *tx.gas_price(); - let gas_limit = *tx.gas_limit(); - *tx.gas_price_mut() = 0; - *tx.gas_limit_mut() = consensus_parameters.max_gas_per_tx; - - tx.estimate_predicates(consensus_parameters, gas_costs)?; - *tx.gas_price_mut() = gas_price; - *tx.gas_limit_mut() = gas_limit; - - Ok(()) -} diff --git a/packages/fuels/tests/contracts.rs b/packages/fuels/tests/contracts.rs index f1f4f83c83..bc00239c36 100644 --- a/packages/fuels/tests/contracts.rs +++ b/packages/fuels/tests/contracts.rs @@ -1648,7 +1648,7 @@ async fn heap_types_correctly_offset_in_create_transactions_w_storage_slots() -> )? .with_data(data) .with_provider(provider); - let wallet: WalletUnlocked = wallet; + wallet .transfer( predicate.address(), diff --git a/packages/fuels/tests/predicates.rs b/packages/fuels/tests/predicates.rs index 8df446c800..6e42bde10f 100644 --- a/packages/fuels/tests/predicates.rs +++ b/packages/fuels/tests/predicates.rs @@ -814,19 +814,8 @@ async fn predicate_can_access_manually_added_witnesses() -> Result<()> { let witness = ABIEncoder::encode(&[64u8.into_token()])?.resolve(0); let witness2 = ABIEncoder::encode(&[4096u64.into_token()])?.resolve(0); - tx.append_witness( - witness.into(), - &network_info.chain_id(), - &network_info.consensus_parameters, - &network_info.gas_costs, - )?; - - tx.append_witness( - witness2.into(), - &network_info.chain_id(), - &network_info.consensus_parameters, - &network_info.gas_costs, - )?; + tx.append_witness(witness.into()); + tx.append_witness(witness2.into()); provider.send_transaction_and_await_commit(tx).await?; diff --git a/packages/fuels/tests/wallets.rs b/packages/fuels/tests/wallets.rs index 5fb71465e7..897a23775d 100644 --- a/packages/fuels/tests/wallets.rs +++ b/packages/fuels/tests/wallets.rs @@ -1,6 +1,6 @@ use std::iter::repeat; -use fuel_tx::{input::coin::CoinSigned, Bytes32, Input, Output, TxPointer, UtxoId, Witness}; +use fuel_tx::{input::coin::CoinSigned, Bytes32, Input, Output, TxPointer, UtxoId}; use fuels::{prelude::*, types::transaction_builders::ScriptTransactionBuilder}; use fuels_accounts::wallet::{Wallet, WalletUnlocked}; use fuels_core::types::transaction_builders::TransactionBuilder;