From f996863e84b4557bb48db9367ed17bd85e5c297b Mon Sep 17 00:00:00 2001 From: MujkicA <32431923+MujkicA@users.noreply.github.com> Date: Wed, 27 Sep 2023 23:41:21 +0200 Subject: [PATCH] feat: pull tx param defaults from network (#1121) Closes #1113 Bundles relevant NodeInfo and ChainInfo field to NetworkInfo so that it can be provided to a tx builder. The builder is then able to use default values for unset tx parameters. --------- Co-authored-by: hal3e --- docs/src/calling-contracts/tx-params.md | 6 +- docs/src/connecting/external-node.md | 2 +- examples/cookbook/src/lib.rs | 9 +- packages/fuels-accounts/src/lib.rs | 31 ++- packages/fuels-accounts/src/predicate.rs | 2 - packages/fuels-accounts/src/provider.rs | 8 + packages/fuels-accounts/src/wallet.rs | 2 - .../src/types/transaction_builders.rs | 206 +++++++++++------- .../fuels-core/src/types/wrappers/block.rs | 4 +- .../src/types/wrappers/chain_info.rs | 3 + .../src/types/wrappers/node_info.rs | 2 +- .../src/types/wrappers/transaction.rs | 78 +++---- packages/fuels-core/src/utils/constants.rs | 6 - packages/fuels-programs/src/call_utils.rs | 8 +- packages/fuels-programs/src/contract.rs | 3 + packages/fuels-programs/src/script_calls.rs | 12 +- packages/fuels/tests/predicates.rs | 23 +- packages/fuels/tests/providers.rs | 32 ++- packages/fuels/tests/wallets.rs | 27 ++- 19 files changed, 289 insertions(+), 175 deletions(-) diff --git a/docs/src/calling-contracts/tx-params.md b/docs/src/calling-contracts/tx-params.md index 2b8fcfaf4e..3b7bdb64a8 100644 --- a/docs/src/calling-contracts/tx-params.md +++ b/docs/src/calling-contracts/tx-params.md @@ -17,13 +17,9 @@ You can configure these parameters by creating an instance of `TxParameters` and -You can also use `TxParameters::default()` to use the default values: +You can also use `TxParameters::default()` to use the default values. If `gas_price` or `gas_limit` is set to `None`, the SDK will use the network's default value: -```rust,ignore -{{#include ../../../packages/fuels-core/src/utils/constants.rs:default_tx_parameters}} -``` - This way: ```rust,ignore diff --git a/docs/src/connecting/external-node.md b/docs/src/connecting/external-node.md index b00cae3f82..08e3b47fa9 100644 --- a/docs/src/connecting/external-node.md +++ b/docs/src/connecting/external-node.md @@ -14,7 +14,7 @@ In the code example, we connected a new provider to the Testnet node and created > **Note:** New wallets on the Testnet will not have any assets! They can be obtained by providing the wallet address to the faucet at > ->[faucet-beta-3.fuel.network](https://faucet-beta-3.fuel.network) +>[faucet-beta-4.fuel.network](https://faucet-beta-4.fuel.network) > > Once the assets have been transferred to the wallet, you can reuse it in other tests by providing the private key! > diff --git a/examples/cookbook/src/lib.rs b/examples/cookbook/src/lib.rs index 6113a8a765..1d7fccd4fb 100644 --- a/examples/cookbook/src/lib.rs +++ b/examples/cookbook/src/lib.rs @@ -166,8 +166,13 @@ mod tests { // ANCHOR_END: transfer_multiple_inout // ANCHOR: transfer_multiple_transaction - let mut tb = - ScriptTransactionBuilder::prepare_transfer(inputs, outputs, TxParameters::default()); + let network_info = provider.network_info().await?; + let mut tb = ScriptTransactionBuilder::prepare_transfer( + inputs, + outputs, + TxParameters::default(), + network_info, + ); wallet_1.sign_transaction(&mut tb); let tx = tb.build()?; diff --git a/packages/fuels-accounts/src/lib.rs b/packages/fuels-accounts/src/lib.rs index 8ea265a590..98245ca2aa 100644 --- a/packages/fuels-accounts/src/lib.rs +++ b/packages/fuels-accounts/src/lib.rs @@ -186,15 +186,18 @@ pub trait Account: ViewOnlyAccount { tx_parameters: TxParameters, ) -> Result<(TxId, Vec)> { let provider = self.try_provider()?; + let network_info = provider.network_info().await?; let inputs = self.get_asset_inputs_for_amount(asset_id, amount).await?; let outputs = self.get_asset_outputs_for_amount(to, asset_id, amount); - let consensus_parameters = provider.consensus_parameters(); - - let tx_builder = ScriptTransactionBuilder::prepare_transfer(inputs, outputs, tx_parameters) - .with_consensus_parameters(consensus_parameters); + let tx_builder = ScriptTransactionBuilder::prepare_transfer( + inputs, + outputs, + tx_parameters, + network_info, + ); // if we are not transferring the base asset, previous base amount is 0 let previous_base_amount = if asset_id == AssetId::default() { @@ -233,6 +236,7 @@ pub trait Account: ViewOnlyAccount { tx_parameters: TxParameters, ) -> std::result::Result<(String, Vec), Error> { let provider = self.try_provider()?; + let network_info = provider.network_info().await?; let zeroes = Bytes32::zeroed(); let plain_contract_id: ContractId = to.into(); @@ -253,8 +257,6 @@ pub trait Account: ViewOnlyAccount { ]; // Build transaction and sign it - let params = provider.consensus_parameters(); - let tb = ScriptTransactionBuilder::prepare_contract_transfer( plain_contract_id, balance, @@ -262,8 +264,8 @@ pub trait Account: ViewOnlyAccount { inputs, outputs, tx_parameters, - ) - .with_consensus_parameters(params); + network_info, + ); // if we are not transferring the base asset, previous base amount is 0 let base_amount = if asset_id == AssetId::default() { @@ -294,6 +296,7 @@ pub trait Account: ViewOnlyAccount { tx_parameters: TxParameters, ) -> std::result::Result<(TxId, MessageId, Vec), Error> { let provider = self.try_provider()?; + let network_info = provider.network_info().await?; let inputs = self .get_asset_inputs_for_amount(BASE_ASSET_ID, amount) @@ -304,6 +307,7 @@ pub trait Account: ViewOnlyAccount { amount, inputs, tx_parameters, + network_info, ); let tx = self.add_fee_resources(tb, amount).await?; @@ -327,7 +331,7 @@ mod tests { use fuel_crypto::{Message, SecretKey}; use fuel_tx::{Address, Output}; - use fuels_core::types::transaction::Transaction; + use fuels_core::types::{transaction::Transaction, transaction_builders::NetworkInfo}; use rand::{rngs::StdRng, RngCore, SeedableRng}; use super::*; @@ -376,6 +380,12 @@ mod tests { )?; let wallet = WalletUnlocked::new_from_private_key(secret, None); + let network_info = NetworkInfo { + consensus_parameters: Default::default(), + max_gas_per_tx: 0, + min_gas_price: 0, + gas_costs: Default::default(), + }; // Set up a transaction let mut tb = { let input_coin = Input::ResourceSigned { @@ -398,6 +408,7 @@ mod tests { vec![input_coin], vec![output_coin], Default::default(), + network_info, ) }; @@ -417,7 +428,7 @@ mod tests { assert_eq!(signature, tx_signature); // Check if the signature is what we expect it to be - assert_eq!(signature, Signature::from_str("d7027be16db0aada625ac8cd438f9b6187bd74465495ba39511c1ad72b7bb10af4ef582c94cc33433f7a1eb4f2ad21c471473947f5f645e90924ba273e2cee7f")?); + assert_eq!(signature, Signature::from_str("51198e39c541cd3197785fd8add8cdbec3dc5aba7f8fbb23eb09455dd1003a8b78d94f247df8e1577805ea7eebd6d58336393942fd98484609e9e7d6d7a55f28")?); // Recover the address that signed the transaction let recovered_address = signature.recover(&message)?; diff --git a/packages/fuels-accounts/src/predicate.rs b/packages/fuels-accounts/src/predicate.rs index 510d00db58..6e2e7a2097 100644 --- a/packages/fuels-accounts/src/predicate.rs +++ b/packages/fuels-accounts/src/predicate.rs @@ -146,8 +146,6 @@ impl Account for Predicate { previous_base_amount: u64, ) -> Result { let consensus_parameters = self.try_provider()?.consensus_parameters(); - tb = tb.with_consensus_parameters(consensus_parameters); - let new_base_amount = calculate_base_amount_with_fee(&tb, &consensus_parameters, previous_base_amount)?; diff --git a/packages/fuels-accounts/src/provider.rs b/packages/fuels-accounts/src/provider.rs index aa3da6038f..438dd4395b 100644 --- a/packages/fuels-accounts/src/provider.rs +++ b/packages/fuels-accounts/src/provider.rs @@ -26,6 +26,7 @@ use fuels_core::{ message_proof::MessageProof, node_info::NodeInfo, transaction::Transaction, + transaction_builders::NetworkInfo, transaction_response::TransactionResponse, tx_status::TxStatus, }, @@ -274,6 +275,13 @@ impl Provider { self.consensus_parameters } + pub async fn network_info(&self) -> ProviderResult { + let node_info = self.node_info().await?; + let chain_info = self.chain_info().await?; + + Ok(NetworkInfo::new(node_info, chain_info)) + } + pub fn chain_id(&self) -> ChainId { self.consensus_parameters.chain_id } diff --git a/packages/fuels-accounts/src/wallet.rs b/packages/fuels-accounts/src/wallet.rs index 4aaa9f51c0..907abc63f1 100644 --- a/packages/fuels-accounts/src/wallet.rs +++ b/packages/fuels-accounts/src/wallet.rs @@ -260,8 +260,6 @@ impl Account for WalletUnlocked { previous_base_amount: u64, ) -> Result { let consensus_parameters = self.try_provider()?.consensus_parameters(); - tb = tb.with_consensus_parameters(consensus_parameters); - self.sign_transaction(&mut tb); let new_base_amount = diff --git a/packages/fuels-core/src/types/transaction_builders.rs b/packages/fuels-core/src/types/transaction_builders.rs index 5e87f65211..076c076c8c 100644 --- a/packages/fuels-core/src/types/transaction_builders.rs +++ b/packages/fuels-core/src/types/transaction_builders.rs @@ -9,7 +9,7 @@ use fuel_tx::{ Cacheable, ConsensusParameters, Create, Input as FuelInput, Output, Script, StorageSlot, Transaction as FuelTransaction, TransactionFee, TxPointer, UniqueIdentifier, Witness, }; -use fuel_types::{bytes::padded_len_usize, Bytes32, MemLayout, Salt}; +use fuel_types::{bytes::padded_len_usize, Bytes32, ChainId, MemLayout, Salt}; use fuel_vm::{checked_transaction::EstimatePredicates, gas::GasCosts}; use crate::{ @@ -28,6 +28,31 @@ use crate::{ }, }; +use super::{chain_info::ChainInfo, node_info::NodeInfo}; + +#[derive(Debug, Clone)] +pub struct NetworkInfo { + pub consensus_parameters: ConsensusParameters, + pub max_gas_per_tx: u64, + pub min_gas_price: u64, + pub gas_costs: GasCosts, +} + +impl NetworkInfo { + pub fn new(node_info: NodeInfo, chain_info: ChainInfo) -> Self { + Self { + max_gas_per_tx: chain_info.consensus_parameters.max_gas_per_tx, + consensus_parameters: chain_info.consensus_parameters.into(), + min_gas_price: node_info.min_gas_price, + gas_costs: chain_info.gas_costs, + } + } + + pub fn chain_id(&self) -> ChainId { + self.consensus_parameters.chain_id + } +} + #[derive(Debug, Clone, Default)] struct UnresolvedSignatures { addr_idx_offset_map: HashMap, @@ -47,7 +72,6 @@ pub trait TransactionBuilder: Send { fn with_inputs(self, inputs: Vec) -> Self; fn with_outputs(self, outputs: Vec) -> Self; fn with_witnesses(self, witnesses: Vec) -> Self; - fn with_consensus_parameters(self, consensus_parameters: ConsensusParameters) -> Self; fn inputs(&self) -> &Vec; fn inputs_mut(&mut self) -> &mut Vec; fn outputs(&self) -> &Vec; @@ -62,27 +86,21 @@ macro_rules! impl_tx_trait { type TxType = $tx_ty; fn build(self) -> Result<$tx_ty> { let uses_predicates = self.is_using_predicates(); - let (base_offset, consensus_parameters) = if uses_predicates { - let consensus_params = self - .consensus_parameters - .ok_or(error!( - TransactionBuildError, - "predicate inputs require consensus parameters. Use `.set_consensus_parameters()`."))?; - (self.base_offset(&consensus_params), consensus_params) + let base_offset = if uses_predicates { + self.base_offset() } else { - // If no ConsensusParameters have been set, we can use the default instead of - // erroring out since the tx doesn't use predicates - (0, self.consensus_parameters.unwrap_or_default()) + 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, &consensus_parameters)?; + let mut tx = self.resolve_fuel_tx(base_offset, num_witnesses)?; - tx.precompute(&consensus_parameters.chain_id)?; + tx.precompute(&network_info.chain_id())?; if uses_predicates { - estimate_predicates(&mut tx, &consensus_parameters)?; + estimate_predicates(&mut tx, &network_info)?; }; Ok($tx_ty { tx }) @@ -91,10 +109,15 @@ macro_rules! impl_tx_trait { fn add_unresolved_signature(&mut self, owner: Bech32Address, secret_key: SecretKey) { let index_offset = self.unresolved_signatures.secret_keys.len() as u8; self.unresolved_signatures.secret_keys.push(secret_key); - self.unresolved_signatures.addr_idx_offset_map.insert(owner, index_offset); + self.unresolved_signatures + .addr_idx_offset_map + .insert(owner, index_offset); } - fn fee_checked_from_tx(&self, params: &ConsensusParameters) -> Result>{ + fn fee_checked_from_tx( + &self, + params: &ConsensusParameters, + ) -> Result> { let tx = self.clone().build()?.tx; Ok(TransactionFee::checked_from_tx(params, &tx)) } @@ -105,19 +128,20 @@ macro_rules! impl_tx_trait { } fn with_gas_price(mut self, gas_price: u64) -> Self { - self.gas_price = gas_price; + self.gas_price = Some(gas_price); self } fn with_gas_limit(mut self, gas_limit: u64) -> Self { - self.gas_limit = gas_limit; + self.gas_limit = Some(gas_limit); self } - fn with_tx_params(self, tx_params: TxParameters) -> Self { - self.with_gas_limit(tx_params.gas_limit()) - .with_gas_price(tx_params.gas_price()) - .with_maturity(tx_params.maturity().into()) + fn with_tx_params(mut self, tx_params: TxParameters) -> Self { + self.gas_limit = tx_params.gas_limit(); + self.gas_price = tx_params.gas_price(); + + self.with_maturity(tx_params.maturity().into()) } fn with_inputs(mut self, inputs: Vec) -> Self { @@ -135,14 +159,6 @@ macro_rules! impl_tx_trait { self } - fn with_consensus_parameters( - mut self, - consensus_parameters: ConsensusParameters, - ) -> Self { - self.consensus_parameters = Some(consensus_parameters); - self - } - fn inputs(&self) -> &Vec { self.inputs.as_ref() } @@ -176,12 +192,13 @@ macro_rules! impl_tx_trait { } fn num_witnesses(&self) -> Result { - let num_witnesses = self - .witnesses() - .len(); + let num_witnesses = self.witnesses().len(); if num_witnesses + self.unresolved_signatures.secret_keys.len() > 256 { - return Err(error!(InvalidData, "tx can not have more than 256 witnesses")); + return Err(error!( + InvalidData, + "tx can not have more than 256 witnesses" + )); } Ok(num_witnesses as u8) @@ -190,24 +207,24 @@ macro_rules! impl_tx_trait { }; } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct ScriptTransactionBuilder { - pub gas_price: u64, - pub gas_limit: u64, + pub gas_price: Option, + pub gas_limit: Option, pub maturity: u32, pub script: Vec, pub script_data: Vec, pub inputs: Vec, pub outputs: Vec, pub witnesses: Vec, - pub(crate) consensus_parameters: Option, + pub(crate) network_info: NetworkInfo, unresolved_signatures: UnresolvedSignatures, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct CreateTransactionBuilder { - pub gas_price: u64, - pub gas_limit: u64, + pub gas_price: Option, + pub gas_limit: Option, pub maturity: u32, pub bytecode_length: u64, pub bytecode_witness_index: u8, @@ -216,7 +233,7 @@ pub struct CreateTransactionBuilder { pub outputs: Vec, pub witnesses: Vec, pub salt: Salt, - pub(crate) consensus_parameters: Option, + pub(crate) network_info: NetworkInfo, unresolved_signatures: UnresolvedSignatures, } @@ -224,15 +241,28 @@ impl_tx_trait!(ScriptTransactionBuilder, ScriptTransaction); impl_tx_trait!(CreateTransactionBuilder, CreateTransaction); impl ScriptTransactionBuilder { - fn resolve_fuel_tx( - self, - base_offset: usize, - num_witnesses: u8, - consensus_parameters: &ConsensusParameters, - ) -> Result