diff --git a/docs/src/connecting/short-lived.md b/docs/src/connecting/short-lived.md index a8fdde7c..31d6f1ca 100644 --- a/docs/src/connecting/short-lived.md +++ b/docs/src/connecting/short-lived.md @@ -17,7 +17,7 @@ You can also use the test helper `setup_test_provider()` for this: You can also use `launch_provider_and_get_wallet()`, which abstracts away the `setup_test_provider()` and the wallet creation, all in one single method: ```rust,ignore -let wallet = launch_provider_and_get_wallet().await; +let wallet = launch_provider_and_get_wallet().await?; ``` ## Features diff --git a/examples/contracts/src/lib.rs b/examples/contracts/src/lib.rs index de1a0744..4b1c6f36 100644 --- a/examples/contracts/src/lib.rs +++ b/examples/contracts/src/lib.rs @@ -2,28 +2,20 @@ mod tests { use fuels::{ core::codec::DecoderConfig, - prelude::{LoadConfiguration, StorageConfiguration}, - types::{ - errors::{error, Error, Result}, - Bits256, - }, + prelude::{Config, LoadConfiguration, StorageConfiguration}, + types::{errors::Result, Bits256}, }; #[tokio::test] async fn instantiate_client() -> Result<()> { // ANCHOR: instantiate_client - use fuels::{ - fuel_node::{Config, FuelService}, - prelude::Provider, - }; + use fuels::prelude::{FuelService, Provider}; // Run the fuel node. - let server = FuelService::new_node(Config::local_node()) - .await - .map_err(|err| error!(InfrastructureError, "{err}"))?; + let server = FuelService::start(Config::local_node()).await?; // Create a client that will talk to the node created above. - let client = Provider::from(server.bound_address).await?; + let client = Provider::from(server.bound_address()).await?; assert!(client.healthy().await?); // ANCHOR_END: instantiate_client Ok(()) @@ -35,7 +27,7 @@ mod tests { // ANCHOR: deploy_contract // This helper will launch a local node and provide a test wallet linked to it - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; // This will load and deploy your contract binary to the chain so that its ID can // be used to initialize the instance @@ -91,7 +83,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -124,7 +116,7 @@ mod tests { }; use rand::prelude::{Rng, SeedableRng, StdRng}; - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id_1 = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -224,7 +216,7 @@ mod tests { )); let wallets = - launch_custom_provider_and_get_wallets(WalletsConfig::default(), None, None).await; + launch_custom_provider_and_get_wallets(WalletsConfig::default(), None, None).await?; let contract_id_1 = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -275,7 +267,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -345,7 +337,7 @@ mod tests { abi = "packages/fuels/tests/contracts/token_ops/out/debug/token_ops-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/token_ops/out/debug/token_ops\ @@ -385,7 +377,7 @@ mod tests { abi="packages/fuels/tests/contracts/lib_contract_caller/out/debug/lib_contract_caller-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let called_contract_id: ContractId = Contract::load_from( "../../packages/fuels/tests/contracts/lib_contract/out/debug/lib_contract.bin", @@ -456,7 +448,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -501,7 +493,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet_original = launch_provider_and_get_wallet().await; + let wallet_original = launch_provider_and_get_wallet().await?; let wallet = wallet_original.clone(); // Your bech32m encoded contract ID. @@ -536,7 +528,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -574,7 +566,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -630,7 +622,7 @@ mod tests { abi = "packages/fuels/tests/contracts/contract_test/out/debug/contract_test-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "../../packages/fuels/tests/contracts/contract_test/out/debug/contract_test.bin", @@ -672,7 +664,7 @@ mod tests { )); let config = WalletsConfig::new(Some(2), Some(1), Some(DEFAULT_COIN_AMOUNT)); - let mut wallets = launch_custom_provider_and_get_wallets(config, None, None).await; + let mut wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; let wallet_1 = wallets.pop().unwrap(); let wallet_2 = wallets.pop().unwrap(); diff --git a/examples/cookbook/src/lib.rs b/examples/cookbook/src/lib.rs index 1d7fccd4..71f84e94 100644 --- a/examples/cookbook/src/lib.rs +++ b/examples/cookbook/src/lib.rs @@ -38,7 +38,7 @@ mod tests { .into(); let wallet_config = WalletsConfig::new_multiple_assets(1, asset_configs); - let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await?; let wallet = &wallets[0]; // ANCHOR_END: liquidity_wallet @@ -91,7 +91,7 @@ mod tests { #[tokio::test] async fn custom_chain() -> Result<()> { // ANCHOR: custom_chain_import - use fuels::{fuel_node::ChainConfig, prelude::*, tx::ConsensusParameters}; + use fuels::{prelude::*, tx::ConsensusParameters}; // ANCHOR_END: custom_chain_import // ANCHOR: custom_chain_consensus @@ -118,7 +118,7 @@ mod tests { // ANCHOR: custom_chain_provider let node_config = Config::local_node(); let _provider = - setup_test_provider(coins, vec![], Some(node_config), Some(chain_config)).await; + setup_test_provider(coins, vec![], Some(node_config), Some(chain_config)).await?; // ANCHOR_END: custom_chain_provider Ok(()) } @@ -138,7 +138,7 @@ mod tests { let (coins, _) = setup_multiple_assets_coins(wallet_1.address(), NUM_ASSETS, NUM_COINS, AMOUNT); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; wallet_1.set_provider(provider.clone()); wallet_2.set_provider(provider.clone()); @@ -195,17 +195,15 @@ mod tests { use std::path::PathBuf; use fuels::prelude::*; - // ANCHOR: create_or_use_rocksdb let provider_config = Config { - database_path: PathBuf::from("/tmp/.spider/db"), - database_type: DbType::RocksDb, + database_type: DbType::RocksDb(Some(PathBuf::from("/tmp/.spider/db"))), ..Config::local_node() }; // ANCHOR_END: create_or_use_rocksdb launch_custom_provider_and_get_wallets(Default::default(), Some(provider_config), None) - .await; + .await?; Ok(()) } diff --git a/examples/predicates/src/lib.rs b/examples/predicates/src/lib.rs index 7f4f3913..26750e6e 100644 --- a/examples/predicates/src/lib.rs +++ b/examples/predicates/src/lib.rs @@ -44,7 +44,7 @@ mod tests { }) .collect::>(); - let provider = setup_test_provider(all_coins, vec![], None, None).await; + let provider = setup_test_provider(all_coins, vec![], None, None).await?; [&mut wallet, &mut wallet2, &mut wallet3, &mut receiver] .iter_mut() @@ -138,7 +138,7 @@ mod tests { }], ); - let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await; + let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await?; let first_wallet = &wallets[0]; let second_wallet = &wallets[1]; diff --git a/examples/providers/src/lib.rs b/examples/providers/src/lib.rs index 0da4b44e..e2864ce3 100644 --- a/examples/providers/src/lib.rs +++ b/examples/providers/src/lib.rs @@ -5,7 +5,7 @@ mod tests { use fuels::prelude::Result; #[tokio::test] - async fn connect_to_fuel_node() { + async fn connect_to_fuel_node() -> Result<()> { // ANCHOR: connect_to_testnet use std::str::FromStr; @@ -28,7 +28,7 @@ mod tests { dbg!(wallet.address().to_string()); // ANCHOR_END: connect_to_testnet - let provider = setup_test_provider(vec![], vec![], None, None).await; + let provider = setup_test_provider(vec![], vec![], None, None).await?; let port = provider.url().split(':').last().unwrap(); // ANCHOR: local_node_address @@ -36,6 +36,7 @@ mod tests { .await .unwrap(); // ANCHOR_END: local_node_address + Ok(()) } #[tokio::test] @@ -66,7 +67,7 @@ mod tests { // ANCHOR: configure_retry let retry_config = RetryConfig::new(3, Backoff::Fixed(Duration::from_secs(2)))?; let provider = setup_test_provider(coins.clone(), vec![], None, None) - .await + .await? .with_retry_config(retry_config); // ANCHOR_END: configure_retry // ANCHOR_END: setup_test_blockchain diff --git a/examples/rust_bindings/src/lib.rs b/examples/rust_bindings/src/lib.rs index b7ab092f..4402e8ed 100644 --- a/examples/rust_bindings/src/lib.rs +++ b/examples/rust_bindings/src/lib.rs @@ -6,7 +6,7 @@ mod tests { #[allow(unused_variables)] async fn transform_json_to_bindings() -> Result<()> { use fuels::test_helpers::launch_provider_and_get_wallet; - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; { // ANCHOR: use_abigen use fuels::prelude::*; diff --git a/examples/wallets/src/lib.rs b/examples/wallets/src/lib.rs index 10808f78..5590113a 100644 --- a/examples/wallets/src/lib.rs +++ b/examples/wallets/src/lib.rs @@ -3,16 +3,18 @@ mod tests { use fuels::prelude::*; #[tokio::test] - async fn create_random_wallet() { + async fn create_random_wallet() -> Result<()> { // ANCHOR: create_random_wallet use fuels::prelude::*; // Use the test helper to setup a test provider. - let provider = setup_test_provider(vec![], vec![], None, None).await; + let provider = setup_test_provider(vec![], vec![], None, None).await?; // Create the wallet. let _wallet = WalletUnlocked::new_random(Some(provider)); // ANCHOR_END: create_random_wallet + + Ok(()) } #[tokio::test] @@ -24,7 +26,7 @@ mod tests { use fuels::{accounts::fuel_crypto::SecretKey, prelude::*}; // Use the test helper to setup a test provider. - let provider = setup_test_provider(vec![], vec![], None, None).await; + let provider = setup_test_provider(vec![], vec![], None, None).await?; // Setup the private key. let secret = SecretKey::from_str( @@ -46,7 +48,7 @@ mod tests { "oblige salon price punch saddle immune slogan rare snap desert retire surprise"; // Use the test helper to setup a test provider. - let provider = setup_test_provider(vec![], vec![], None, None).await; + let provider = setup_test_provider(vec![], vec![], None, None).await?; // Create first account from mnemonic phrase. let _wallet = WalletUnlocked::new_from_mnemonic_phrase_with_path( @@ -74,7 +76,7 @@ mod tests { let mut rng = rand::thread_rng(); // Use the test helper to setup a test provider. - let provider = setup_test_provider(vec![], vec![], None, None).await; + let provider = setup_test_provider(vec![], vec![], None, None).await?; let password = "my_master_password"; @@ -100,7 +102,7 @@ mod tests { "oblige salon price punch saddle immune slogan rare snap desert retire surprise"; // Use the test helper to setup a test provider. - let provider = setup_test_provider(vec![], vec![], None, None).await; + let provider = setup_test_provider(vec![], vec![], None, None).await?; // Create first account from mnemonic phrase. let wallet = WalletUnlocked::new_from_mnemonic_phrase(phrase, Some(provider))?; @@ -128,7 +130,7 @@ mod tests { None, None, ) - .await; + .await?; // Transfer the base asset with amount 1 from wallet 1 to wallet 2 let asset_id = Default::default(); @@ -168,7 +170,7 @@ mod tests { let wallet_config = WalletsConfig::new_multiple_assets(1, vec![random_asset, base_asset]); let wallet = launch_custom_provider_and_get_wallets(wallet_config, None, None) - .await + .await? .pop() .unwrap(); @@ -216,7 +218,7 @@ mod tests { // This helper will launch a local node and provide 10 test wallets linked to it. // The initial balance defaults to 1 coin per wallet with an amount of 1_000_000_000 let wallets = - launch_custom_provider_and_get_wallets(WalletsConfig::default(), None, None).await; + launch_custom_provider_and_get_wallets(WalletsConfig::default(), None, None).await?; // ANCHOR_END: multiple_wallets_helper // ANCHOR: setup_5_wallets let num_wallets = 5; @@ -229,7 +231,7 @@ mod tests { Some(amount_per_coin), ); // Launches a local node and provides test wallets as specified by the config - let wallets = launch_custom_provider_and_get_wallets(config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; // ANCHOR_END: setup_5_wallets Ok(()) } @@ -252,7 +254,7 @@ mod tests { amount_per_coin, ); // ANCHOR_END: multiple_assets_coins - let provider = setup_test_provider(coins.clone(), vec![], None, None).await; + let provider = setup_test_provider(coins.clone(), vec![], None, None).await?; wallet.set_provider(provider); // ANCHOR_END: multiple_assets_wallet Ok(()) @@ -260,7 +262,7 @@ mod tests { #[tokio::test] #[allow(unused_variables)] - async fn setup_wallet_custom_assets() -> std::result::Result<(), rand::Error> { + async fn setup_wallet_custom_assets() -> std::result::Result<(), Box> { // ANCHOR: custom_assets_wallet use fuels::prelude::*; use rand::Fill; @@ -293,13 +295,13 @@ mod tests { let assets = vec![asset_base, asset_1, asset_2]; let coins = setup_custom_assets_coins(wallet.address(), &assets); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; wallet.set_provider(provider); // ANCHOR_END: custom_assets_wallet // ANCHOR: custom_assets_wallet_short let num_wallets = 1; let wallet_config = WalletsConfig::new_multiple_assets(num_wallets, assets); - let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await?; // ANCHOR_END: custom_assets_wallet_short Ok(()) } @@ -317,7 +319,7 @@ mod tests { types::AssetId, }; - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; // ANCHOR: get_asset_balance let asset_id: AssetId = BASE_ASSET_ID; let balance: u64 = wallet.get_asset_balance(&asset_id).await?; @@ -351,7 +353,7 @@ mod tests { Some(config), None, ) - .await; + .await?; let wallet = wallets.first().unwrap(); let amount = 1000; diff --git a/packages/fuels-accounts/Cargo.toml b/packages/fuels-accounts/Cargo.toml index 8ec391ef..0823fc93 100644 --- a/packages/fuels-accounts/Cargo.toml +++ b/packages/fuels-accounts/Cargo.toml @@ -14,7 +14,6 @@ async-trait = { workspace = true, default-features = false } chrono = { workspace = true } elliptic-curve = { workspace = true, default-features = false } eth-keystore = { workspace = true } -fuel-core = { workspace = true, default-features = false, optional = true } fuel-core-client = { workspace = true, features = ["default"] } fuel-crypto = { workspace = true, features = ["random"] } fuel-tx = { workspace = true } diff --git a/packages/fuels-accounts/src/provider.rs b/packages/fuels-accounts/src/provider.rs index 8290afa8..5cfca1f5 100644 --- a/packages/fuels-accounts/src/provider.rs +++ b/packages/fuels-accounts/src/provider.rs @@ -4,8 +4,6 @@ mod retry_util; mod retryable_client; use chrono::{DateTime, Utc}; -#[cfg(feature = "fuel-core-lib")] -use fuel_core::service::{Config, FuelService}; use fuel_core_client::client::{ pagination::{PageDirection, PaginatedResult, PaginationRequest}, types::{balance::Balance, contract::ContractBalance, TransactionStatus}, @@ -36,7 +34,6 @@ use tai64::Tai64; use thiserror::Error; use crate::provider::retryable_client::RetryableClient; - type ProviderResult = std::result::Result; #[derive(Debug)] @@ -260,13 +257,6 @@ impl Provider { Ok(status) } - #[cfg(feature = "fuel-core-lib")] - /// Launches a local `fuel-core` network based on provided config. - pub async fn launch(config: Config) -> Result { - let srv = FuelService::new_node(config).await.unwrap(); - Ok(FuelClient::from(srv.bound_address)) - } - pub async fn chain_info(&self) -> ProviderResult { Ok(self.client.chain_info().await?.into()) } @@ -380,6 +370,7 @@ impl Provider { .flatten() .map(|c| CoinType::try_from(c).map_err(ProviderError::ClientRequestError)) .collect::>>()?; + Ok(res) } diff --git a/packages/fuels-accounts/src/wallet.rs b/packages/fuels-accounts/src/wallet.rs index 1c587e3f..f63c8d60 100644 --- a/packages/fuels-accounts/src/wallet.rs +++ b/packages/fuels-accounts/src/wallet.rs @@ -273,10 +273,8 @@ impl Account for WalletUnlocked { let new_base_inputs = self .get_asset_inputs_for_amount(BASE_ASSET_ID, new_base_amount) .await?; - adjust_inputs(&mut tb, new_base_inputs); adjust_outputs(&mut tb, self.address(), new_base_amount); - tb.build() } } diff --git a/packages/fuels-macros/src/setup_program_test/code_gen.rs b/packages/fuels-macros/src/setup_program_test/code_gen.rs index e52f7638..cc5de807 100644 --- a/packages/fuels-macros/src/setup_program_test/code_gen.rs +++ b/packages/fuels-macros/src/setup_program_test/code_gen.rs @@ -88,6 +88,7 @@ fn wallet_initialization_code(maybe_command: Option) -> None, ) .await + .expect("Error while trying to fetch wallets from the custom provider") .try_into() .expect("Should have the exact number of wallets"); } diff --git a/packages/fuels-test-helpers/Cargo.toml b/packages/fuels-test-helpers/Cargo.toml index 1afa011f..a99dc7b6 100644 --- a/packages/fuels-test-helpers/Cargo.toml +++ b/packages/fuels-test-helpers/Cargo.toml @@ -13,6 +13,8 @@ description = "Fuel Rust SDK test helpers." fuel-core = { workspace = true, default-features = false, optional = true } fuel-core-chain-config = { workspace = true } fuel-core-client = { workspace = true } +fuel-core-services = "0.20.5" +fuel-core-poa = "0.20.5" fuel-tx = { workspace = true } fuel-types = { workspace = true, features = ["random"] } fuels-accounts = { workspace = true, optional = true } diff --git a/packages/fuels-test-helpers/src/accounts.rs b/packages/fuels-test-helpers/src/accounts.rs index c1525ed2..7e70240b 100644 --- a/packages/fuels-test-helpers/src/accounts.rs +++ b/packages/fuels-test-helpers/src/accounts.rs @@ -1,12 +1,9 @@ use std::mem::size_of; -#[cfg(feature = "fuel-core-lib")] -use fuel_core::service::Config; -use fuel_core_chain_config::ChainConfig; +use crate::node_types::{ChainConfig, Config}; use fuels_accounts::{fuel_crypto::SecretKey, wallet::WalletUnlocked, ViewOnlyAccount}; +use fuels_core::types::errors::Result; -#[cfg(not(feature = "fuel-core-lib"))] -use crate::node::Config; use crate::{setup_custom_assets_coins, setup_test_provider, wallets_config::*}; /// Launches a local Fuel node, instantiates a provider, and returns a wallet. @@ -18,17 +15,17 @@ use crate::{setup_custom_assets_coins, setup_test_provider, wallets_config::*}; /// use fuels_accounts::Signer; /// /// async fn single_wallet() -> Result<(), Box> { -/// let wallet = launch_provider_and_get_wallet().await; +/// let wallet = launch_provider_and_get_wallet().await?; /// dbg!(wallet.address()); /// Ok(()) /// } /// ``` -pub async fn launch_provider_and_get_wallet() -> WalletUnlocked { +pub async fn launch_provider_and_get_wallet() -> Result { let mut wallets = launch_custom_provider_and_get_wallets(WalletsConfig::new(Some(1), None, None), None, None) - .await; + .await?; - wallets.pop().unwrap() + Ok(wallets.pop().expect("should have one wallet")) } /// Launches a custom node and provider, along with a configurable number of wallets. @@ -45,7 +42,7 @@ pub async fn launch_provider_and_get_wallet() -> WalletUnlocked { /// let amount = 1; /// let config = WalletsConfig::new(Some(num_wallets), Some(num_coins), Some(amount)); /// -/// let mut wallets = launch_custom_provider_and_get_wallets(config, None, None).await; +/// let mut wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; /// let first_wallet = wallets.pop().unwrap(); /// dbg!(first_wallet.address()); /// Ok(()) @@ -55,7 +52,7 @@ pub async fn launch_custom_provider_and_get_wallets( wallet_config: WalletsConfig, provider_config: Option, chain_config: Option, -) -> Vec { +) -> Result> { const SIZE_SECRET_KEY: usize = size_of::(); const PADDING_BYTES: usize = SIZE_SECRET_KEY - size_of::(); let mut secret_key: [u8; SIZE_SECRET_KEY] = [0; SIZE_SECRET_KEY]; @@ -77,13 +74,13 @@ pub async fn launch_custom_provider_and_get_wallets( .flat_map(|wallet| setup_custom_assets_coins(wallet.address(), wallet_config.assets())) .collect::>(); - let provider = setup_test_provider(all_coins, vec![], provider_config, chain_config).await; + let provider = setup_test_provider(all_coins, vec![], provider_config, chain_config).await?; for wallet in &mut wallets { wallet.set_provider(provider.clone()); } - wallets + Ok(wallets) } #[cfg(test)] @@ -104,7 +101,7 @@ mod tests { let amount = 100; let config = WalletsConfig::new(Some(num_wallets), Some(num_coins), Some(amount)); - let wallets = launch_custom_provider_and_get_wallets(config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; assert_eq!(wallets.len(), num_wallets as usize); @@ -151,7 +148,7 @@ mod tests { let assets = vec![asset_base, asset_1, asset_2]; let config = WalletsConfig::new_multiple_assets(num_wallets, assets.clone()); - let wallets = launch_custom_provider_and_get_wallets(config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; assert_eq!(wallets.len(), num_wallets as usize); for asset in assets { @@ -182,7 +179,7 @@ mod tests { let amount = 100; let config = WalletsConfig::new(Some(num_wallets), Some(num_coins), Some(amount)); - let wallets = launch_custom_provider_and_get_wallets(config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; assert_eq!( wallets.get(31).unwrap().address().to_string(), @@ -208,7 +205,7 @@ mod tests { None, Some(chain_config), ) - .await; + .await?; assert_eq!(wallets.len(), 4); diff --git a/packages/fuels-test-helpers/src/fuel_bin_service.rs b/packages/fuels-test-helpers/src/fuel_bin_service.rs new file mode 100644 index 00000000..dda28327 --- /dev/null +++ b/packages/fuels-test-helpers/src/fuel_bin_service.rs @@ -0,0 +1,220 @@ +use fuels_core::types::errors::{Error, Result as FuelResult}; +use tempfile::NamedTempFile; + +use fuel_core_client::client::FuelClient; +use fuel_core_services::State; +use std::{net::SocketAddr, path::PathBuf, time::Duration}; + +use crate::node_types::{Config, DbType, Trigger}; +use fuels_core::error; +use portpicker::{is_free, pick_unused_port}; +use tokio::{process::Command, spawn, task::JoinHandle, time::sleep}; + +#[derive(Debug)] +struct ExtendedConfig { + config: Config, + config_file: NamedTempFile, +} + +impl ExtendedConfig { + pub fn config_to_args_vec(&mut self) -> FuelResult> { + self.write_temp_chain_config_file()?; + + let port = self.config.addr.port().to_string(); + let mut args = vec![ + "run".to_string(), // `fuel-core` is now run with `fuel-core run` + "--ip".to_string(), + "127.0.0.1".to_string(), + "--port".to_string(), + port, + "--chain".to_string(), + self.config_file + .path() + .to_str() + .expect("Failed to find config file") + .to_string(), + ]; + + args.push("--db-type".to_string()); + match &self.config.database_type { + DbType::InMemory => args.push("in-memory".to_string()), + DbType::RocksDb(path_to_db) => { + args.push("rocks-db".to_string()); + let path = path_to_db.as_ref().cloned().unwrap_or_else(|| { + PathBuf::from(std::env::var("HOME").expect("HOME env var missing")) + .join(".fuel/db") + }); + args.push("--db-path".to_string()); + args.push(path.to_string_lossy().to_string()); + } + } + + if let Some(cache_size) = self.config.max_database_cache_size { + args.push("--max-database-cache-size".to_string()); + args.push(cache_size.to_string()); + } + + match self.config.block_production { + Trigger::Instant => { + args.push("--poa-instant=true".to_string()); + } + Trigger::Never => { + args.push("--poa-instant=false".to_string()); + } + Trigger::Interval { block_time } => { + args.push(format!( + "--poa-interval-period={}ms", + block_time.as_millis() + )); + } + Trigger::Hybrid { + min_block_time, + max_tx_idle_time, + max_block_time, + } => { + args.push(format!( + "--poa-hybrid-min-time={}ms", + min_block_time.as_millis() + )); + args.push(format!( + "--poa-hybrid-idle-time={}ms", + max_tx_idle_time.as_millis() + )); + args.push(format!( + "--poa-hybrid-max-time={}ms", + max_block_time.as_millis() + )); + } + }; + + args.extend( + [ + (self.config.vm_backtrace, "--vm-backtrace"), + (self.config.utxo_validation, "--utxo-validation"), + (self.config.manual_blocks_enabled, "--manual_blocks_enabled"), + ] + .into_iter() + .filter(|(flag, _)| *flag) + .map(|(_, arg)| arg.to_string()), + ); + + Ok(args) + } + + pub fn write_temp_chain_config_file(&mut self) -> FuelResult<()> { + Ok(serde_json::to_writer( + &mut self.config_file, + &self.config.chain_conf, + )?) + } +} + +pub struct FuelService { + pub bound_address: SocketAddr, + handle: JoinHandle<()>, +} + +impl FuelService { + pub async fn new_node(config: Config) -> FuelResult { + let requested_port = config.addr.port(); + + let bound_address = match requested_port { + 0 => get_socket_address(), + _ if is_free(requested_port) => config.addr, + _ => return Err(Error::IOError(std::io::ErrorKind::AddrInUse.into())), + }; + + let config = Config { + addr: bound_address, + ..config + }; + + let extended_config = ExtendedConfig { + config, + config_file: NamedTempFile::new()?, + }; + + let handle = run_node(extended_config).await?; + + Ok(FuelService { + bound_address, + handle, + }) + } + + pub fn stop(&self) -> FuelResult { + self.handle.abort(); + Ok(State::Stopped) + } +} + +async fn server_health_check(client: &FuelClient) -> FuelResult<()> { + let mut attempts = 5; + let mut healthy = client.health().await.unwrap_or(false); + let between_attempts = Duration::from_millis(300); + + while attempts > 0 && !healthy { + healthy = client.health().await.unwrap_or(false); + sleep(between_attempts).await; + attempts -= 1; + } + + if !healthy { + return Err(error!( + InfrastructureError, + "Could not connect to fuel core server." + )); + } + + Ok(()) +} + +fn get_socket_address() -> SocketAddr { + let free_port = pick_unused_port().expect("No ports free"); + SocketAddr::new("127.0.0.1".parse().unwrap(), free_port) +} + +async fn run_node(mut extended_config: ExtendedConfig) -> FuelResult> { + let args = extended_config.config_to_args_vec()?; + + let binary_name = "fuel-core"; + + let paths = which::which_all(binary_name) + .map_err(|_| { + error!( + InfrastructureError, + "failed to list '{}' binaries", binary_name + ) + })? + .collect::>(); + + let path = paths + .first() + .ok_or_else(|| error!(InfrastructureError, "no '{}' in PATH", binary_name))?; + + if paths.len() > 1 { + eprintln!( + "found more than one '{}' binary in PATH, using '{}'", + binary_name, + path.display() + ); + } + + let mut command = Command::new(path); + let running_node = command.args(args).kill_on_drop(true).output(); + + let address = extended_config.config.addr; + let client = FuelClient::from(address); + server_health_check(&client).await?; + + let join_handle = spawn(async move { + let result = running_node + .await + .expect("error: Couldn't find fuel-core in PATH."); + let stdout = String::from_utf8_lossy(&result.stdout); + let stderr = String::from_utf8_lossy(&result.stderr); + eprintln!("the exit status from the fuel binary was: {result:?}, stdout: {stdout}, stderr: {stderr}"); + }); + + Ok(join_handle) +} diff --git a/packages/fuels-test-helpers/src/lib.rs b/packages/fuels-test-helpers/src/lib.rs index 779918b4..4a08d799 100644 --- a/packages/fuels-test-helpers/src/lib.rs +++ b/packages/fuels-test-helpers/src/lib.rs @@ -1,18 +1,11 @@ //! Testing helpers/utilities for Fuel SDK. extern crate core; +use fuel_core_chain_config::StateConfig; + #[cfg(feature = "fuels-accounts")] pub use accounts::*; -#[cfg(feature = "fuel-core-lib")] -pub use fuel_core::service::DbType; -#[cfg(feature = "fuel-core-lib")] -use fuel_core::service::FuelService; -#[cfg(feature = "fuel-core-lib")] -pub use fuel_core::service::{config::Trigger, Config}; -#[cfg(feature = "fuel-core-lib")] -use fuel_core_chain_config::{ChainConfig, StateConfig}; -#[cfg(not(feature = "fuel-core-lib"))] -use fuel_core_client::client::FuelClient; + use fuel_tx::{Bytes32, UtxoId}; use fuel_types::{AssetId, Nonce}; use fuels_accounts::provider::Provider; @@ -21,29 +14,33 @@ use fuels_core::{ types::{ bech32::Bech32Address, coin::{Coin, CoinStatus}, + errors::Result, message::{Message, MessageStatus}, }, }; -#[cfg(not(feature = "fuel-core-lib"))] -pub use node::*; -#[cfg(not(feature = "fuel-core-lib"))] -use portpicker::is_free; + use rand::Fill; -#[cfg(feature = "fuel-core-lib")] -pub use utils::{into_coin_configs, into_message_configs}; +use utils::{into_coin_configs, into_message_configs}; pub use wallets_config::*; +pub use node_types::*; +mod node_types; + #[cfg(not(feature = "fuel-core-lib"))] -pub mod node; +pub(crate) mod fuel_bin_service; #[cfg(feature = "fuels-accounts")] mod accounts; + +pub use service::*; +mod service; + mod utils; mod wallets_config; /// Create a vector of `num_asset`*`coins_per_asset` UTXOs and a vector of the unique corresponding /// asset IDs. `AssetId`. Each UTXO (=coin) contains `amount_per_coin` amount of a random asset. The -/// output of this function can be used with `setup_test_client` to get a client with some +/// output of this function can be used with `setup_test_provider` to get a client with some /// pre-existing coins, with `num_asset` different asset ids. Note that one of the assets is the /// base asset to pay for gas. pub fn setup_multiple_assets_coins( @@ -57,7 +54,9 @@ pub fn setup_multiple_assets_coins( let asset_ids = (0..(num_asset - 1)) .map(|_| { let mut random_asset_id = AssetId::zeroed(); - random_asset_id.try_fill(&mut rng).unwrap(); + random_asset_id + .try_fill(&mut rng) + .expect("failed to fill with random data"); random_asset_id }) .chain([BASE_ASSET_ID]) @@ -83,7 +82,7 @@ pub fn setup_custom_assets_coins(owner: &Bech32Address, assets: &[AssetConfig]) } /// Create a vector of `num_coins` UTXOs containing `amount_per_coin` amount of asset `asset_id`. -/// The output of this function can be used with `setup_test_client` to get a client with some +/// The output of this function can be used with `setup_test_provider` to get a client with some /// pre-existing coins, but with only one asset ID. pub fn setup_single_asset_coins( owner: &Bech32Address, @@ -96,7 +95,8 @@ pub fn setup_single_asset_coins( let coins: Vec = (1..=num_coins) .map(|_i| { let mut r = Bytes32::zeroed(); - r.try_fill(&mut rng).unwrap(); + r.try_fill(&mut rng) + .expect("failed to fill with random data"); let utxo_id = UtxoId::new(r, 0); Coin { @@ -132,13 +132,12 @@ pub fn setup_single_message( } } -#[cfg(feature = "fuel-core-lib")] pub async fn setup_test_provider( coins: Vec, messages: Vec, node_config: Option, chain_config: Option, -) -> Provider { +) -> Result { let coin_configs = into_coin_configs(coins); let message_configs = into_message_configs(messages); let mut chain_conf = chain_config.unwrap_or_else(ChainConfig::local_testnet); @@ -153,53 +152,16 @@ pub async fn setup_test_provider( let mut config = node_config.unwrap_or_else(Config::local_node); config.chain_conf = chain_conf; - let srv = FuelService::new_node(config).await.unwrap(); - let address = srv.bound_address; + let srv = FuelService::start(config).await?; + + let address = srv.bound_address(); + tokio::spawn(async move { let _own_the_handle = srv; let () = futures::future::pending().await; }); - Provider::from(address) - .await - .expect("Could not connect to node") -} - -#[cfg(not(feature = "fuel-core-lib"))] -pub async fn setup_test_provider( - coins: Vec, - messages: Vec, - node_config: Option, - chain_config: Option, -) -> Provider { - let config = node_config.unwrap_or_else(Config::local_node); - let requested_port = config.addr.port(); - - let bound_address = if requested_port == 0 { - get_socket_address() - } else if is_free(requested_port) { - config.addr - } else { - panic!("Error: Address already in use"); - }; - - new_fuel_node( - coins, - messages, - Config { - addr: bound_address, - ..config - }, - chain_config, - ) - .await; - - let client = FuelClient::from(bound_address); - server_health_check(&client).await; - - Provider::from(bound_address) - .await - .expect("Could not connect to node!") + Provider::from(address).await } #[cfg(test)] @@ -212,14 +174,18 @@ mod tests { use super::*; #[tokio::test] - async fn test_setup_single_asset_coins() -> Result<(), rand::Error> { + async fn test_setup_single_asset_coins() -> Result<()> { let mut rng = rand::thread_rng(); let mut addr_data = Bytes32::new([0u8; 32]); - addr_data.try_fill(&mut rng)?; + addr_data + .try_fill(&mut rng) + .expect("failed to fill with random data"); let address = Bech32Address::new("test", addr_data); let mut asset_id = AssetId::zeroed(); - asset_id.try_fill(&mut rng)?; + asset_id + .try_fill(&mut rng) + .expect("failed to fill with random data"); let number_of_coins = 11; let amount_per_coin = 10; @@ -236,10 +202,12 @@ mod tests { } #[tokio::test] - async fn test_setup_multiple_assets_coins() -> Result<(), rand::Error> { + async fn test_setup_multiple_assets_coins() -> Result<()> { let mut rng = rand::thread_rng(); let mut addr_data = Bytes32::new([0u8; 32]); - addr_data.try_fill(&mut rng)?; + addr_data + .try_fill(&mut rng) + .expect("failed to fill with random data"); let address = Bech32Address::new("test", addr_data); let number_of_assets = 7; @@ -275,10 +243,11 @@ mod tests { } #[tokio::test] - async fn test_setup_custom_assets_coins() -> Result<(), rand::Error> { + async fn test_setup_custom_assets_coins() -> Result<()> { let mut rng = rand::thread_rng(); let mut hash = [0u8; 32]; - hash.try_fill(&mut rng)?; + hash.try_fill(&mut rng) + .expect("failed to fill with random data"); let address = Bech32Address::new(FUEL_BECH32_HRP, hash); let asset_base = AssetConfig { @@ -288,7 +257,9 @@ mod tests { }; let mut asset_id_1 = AssetId::zeroed(); - asset_id_1.try_fill(&mut rng)?; + asset_id_1 + .try_fill(&mut rng) + .expect("failed to fill with random data"); let asset_1 = AssetConfig { id: asset_id_1, num_coins: 6, @@ -296,7 +267,9 @@ mod tests { }; let mut asset_id_2 = AssetId::zeroed(); - asset_id_2.try_fill(&mut rng)?; + asset_id_2 + .try_fill(&mut rng) + .expect("failed to fill with random data"); let asset_2 = AssetConfig { id: asset_id_2, num_coins: 10, @@ -322,7 +295,7 @@ mod tests { } #[tokio::test] - async fn test_setup_test_provider_custom_config() -> Result<(), rand::Error> { + async fn test_setup_test_provider_custom_config() -> Result<()> { let socket = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 4000); let config = Config { addr: socket, @@ -331,7 +304,7 @@ mod tests { ..Config::local_node() }; - let provider = setup_test_provider(vec![], vec![], Some(config.clone()), None).await; + let provider = setup_test_provider(vec![], vec![], Some(config.clone()), None).await?; let node_info = provider .node_info() .await @@ -344,7 +317,7 @@ mod tests { } #[tokio::test] - async fn test_setup_test_client_consensus_parameters_config() { + async fn test_setup_test_client_consensus_parameters_config() -> Result<()> { let configured_parameters = ConsensusParameters::DEFAULT .with_max_gas_per_tx(2) .with_gas_per_byte(2) @@ -355,15 +328,16 @@ mod tests { transaction_parameters: configured_parameters, ..ChainConfig::default() }; - let provider = setup_test_provider(vec![], vec![], None, Some(chain_config)).await; + let provider = setup_test_provider(vec![], vec![], None, Some(chain_config)).await?; let retrieved_parameters = provider.consensus_parameters(); assert_eq!(retrieved_parameters, configured_parameters); + Ok(()) } #[tokio::test] - async fn test_chain_config_and_consensus_parameters() { + async fn test_chain_config_and_consensus_parameters() -> Result<()> { let consensus_parameters_config = ConsensusParameters::DEFAULT .with_max_inputs(123) .with_gas_per_byte(456); @@ -374,12 +348,13 @@ mod tests { ..ChainConfig::local_testnet() }; - let provider = setup_test_provider(vec![], vec![], None, Some(chain_config)).await; + let provider = setup_test_provider(vec![], vec![], None, Some(chain_config)).await?; - let chain_info = provider.chain_info().await.unwrap(); + let chain_info = provider.chain_info().await?; assert_eq!(chain_info.name, "Solo_Munib"); assert_eq!(chain_info.consensus_parameters.max_inputs, 123); assert_eq!(chain_info.consensus_parameters.gas_per_byte, 456); + Ok(()) } } diff --git a/packages/fuels-test-helpers/src/node.rs b/packages/fuels-test-helpers/src/node.rs deleted file mode 100644 index e36a58ca..00000000 --- a/packages/fuels-test-helpers/src/node.rs +++ /dev/null @@ -1,411 +0,0 @@ -use std::{ - fmt, - io::Write, - net::{Ipv4Addr, SocketAddr}, - path::PathBuf, - process::Stdio, - time::Duration, -}; - -pub use fuel_core_chain_config::ChainConfig; -use fuel_core_chain_config::StateConfig; -use fuel_core_client::client::FuelClient; -use fuel_types::{BlockHeight, Word}; -use fuels_core::{ - constants::WORD_SIZE, - types::{ - coin::Coin, - errors::{error, Error}, - message::Message, - }, -}; -use portpicker::{is_free, pick_unused_port}; -use serde::{de::Error as SerdeError, Deserializer, Serializer}; -use serde_json::Value; -use serde_with::{DeserializeAs, SerializeAs}; -use tempfile::NamedTempFile; -use tokio::{process::Command, sync::oneshot}; - -use crate::utils::{into_coin_configs, into_message_configs}; -// Set the cache for tests to 10MB, which is the default size in `fuel-core`. -pub const DEFAULT_CACHE_SIZE: usize = 10 * 1024 * 1024; - -#[derive(Clone, Debug)] -pub enum Trigger { - Instant, - Never, - Interval { - block_time: Duration, - }, - Hybrid { - min_block_time: Duration, - max_tx_idle_time: Duration, - max_block_time: Duration, - }, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum DbType { - InMemory, - RocksDb, -} - -#[derive(Clone, Debug)] -pub struct Config { - pub addr: SocketAddr, - pub max_database_cache_size: usize, - pub database_path: PathBuf, - pub database_type: DbType, - pub utxo_validation: bool, - pub manual_blocks_enabled: bool, - pub block_production: Trigger, - pub vm_backtrace: bool, - pub silent: bool, -} - -impl Config { - pub fn local_node() -> Self { - Self { - addr: SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 0), - max_database_cache_size: DEFAULT_CACHE_SIZE, - database_path: Default::default(), - database_type: DbType::InMemory, - utxo_validation: true, - manual_blocks_enabled: false, - block_production: Trigger::Instant, - vm_backtrace: false, - silent: true, - } - } -} - -pub type InternalDaBlockHeight = u64; - -pub(crate) struct HexType; - -impl> SerializeAs for HexType { - fn serialize_as(value: &T, serializer: S) -> Result - where - S: Serializer, - { - serde_hex::serialize(value, serializer) - } -} - -impl<'de, T, E> DeserializeAs<'de, T> for HexType -where - for<'a> T: TryFrom<&'a [u8], Error = E>, - E: fmt::Display, -{ - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - serde_hex::deserialize(deserializer) - } -} - -pub mod serde_hex { - use std::{convert::TryFrom, fmt}; - - use hex::{FromHex, ToHex}; - use serde::{de::Error, Deserializer, Serializer}; - - pub fn serialize(target: T, ser: S) -> Result - where - S: Serializer, - T: ToHex, - { - let s = format!("0x{}", target.encode_hex::()); - ser.serialize_str(&s) - } - - pub fn deserialize<'de, T, E, D>(des: D) -> Result - where - D: Deserializer<'de>, - for<'a> T: TryFrom<&'a [u8], Error = E>, - E: fmt::Display, - { - let raw_string: String = serde::Deserialize::deserialize(des)?; - let stripped_prefix = raw_string.trim_start_matches("0x"); - let bytes: Vec = FromHex::from_hex(stripped_prefix).map_err(D::Error::custom)?; - let result = T::try_from(bytes.as_slice()).map_err(D::Error::custom)?; - Ok(result) - } -} - -pub(crate) struct HexNumber; - -impl SerializeAs for HexNumber { - fn serialize_as(value: &u64, serializer: S) -> Result - where - S: Serializer, - { - let bytes = value.to_be_bytes(); - serde_hex::serialize(bytes, serializer) - } -} - -impl<'de> DeserializeAs<'de, Word> for HexNumber { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let mut bytes: Vec = serde_hex::deserialize(deserializer)?; - match bytes.len() { - len if len > WORD_SIZE => { - return Err(D::Error::custom(format!( - "value can't exceed {WORD_SIZE} bytes", - ))); - } - len if len < WORD_SIZE => { - // pad if length < word size - bytes = (0..WORD_SIZE - len).map(|_| 0u8).chain(bytes).collect(); - } - _ => {} - } - // We've already verified the bytes.len == WORD_SIZE, force the conversion here. - Ok(Word::from_be_bytes( - bytes.try_into().expect("byte lengths checked"), - )) - } -} - -impl SerializeAs for HexNumber { - fn serialize_as(value: &BlockHeight, serializer: S) -> Result - where - S: Serializer, - { - let number = u32::from(*value) as u64; - HexNumber::serialize_as(&number, serializer) - } -} - -impl<'de> DeserializeAs<'de, BlockHeight> for HexNumber { - fn deserialize_as(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let number: u64 = HexNumber::deserialize_as(deserializer)?; - Ok((number as u32).into()) - } -} - -pub fn get_node_config_json( - coins: Vec, - messages: Vec, - chain_config: Option, -) -> Value { - let coin_configs = into_coin_configs(coins); - let messages = into_message_configs(messages); - - let mut chain_config = chain_config.unwrap_or_else(ChainConfig::local_testnet); - - chain_config.initial_state = Some(StateConfig { - coins: Some(coin_configs), - contracts: None, - messages: Some(messages), - height: None, - }); - - serde_json::to_value(&chain_config).expect("Failed to build `ChainConfig` JSON") -} - -fn write_temp_config_file(config: Value) -> NamedTempFile { - let config_file = NamedTempFile::new(); - - let _ = writeln!( - config_file.as_ref().unwrap().as_file(), - "{}", - &config.to_string() - ); - - config_file.unwrap() -} - -pub async fn new_fuel_node( - coins: Vec, - messages: Vec, - config: Config, - chain_config: Option, -) { - // Create a new one-shot channel for sending single values across asynchronous tasks. - let (tx, rx) = oneshot::channel(); - - tokio::spawn(async move { - let config_json = get_node_config_json(coins, messages, chain_config); - - let temp_config_file = write_temp_config_file(config_json); - - let port = config.addr.port().to_string(); - let mut args = vec![ - "run".to_string(), // `fuel-core` is now run with `fuel-core run` - "--ip".to_string(), - "127.0.0.1".to_string(), - "--port".to_string(), - port, - "--chain".to_string(), - temp_config_file.path().to_str().unwrap().to_string(), - ]; - - args.extend(vec![ - "--db-type".to_string(), - match config.database_type { - DbType::InMemory => "in-memory", - DbType::RocksDb => "rocks-db", - } - .to_string(), - ]); - - if let DbType::RocksDb = config.database_type { - let path = if config.database_path.as_os_str().is_empty() { - PathBuf::from(std::env::var("HOME").expect("HOME env var missing")).join(".fuel/db") - } else { - config.database_path - }; - args.extend(vec![ - "--db-path".to_string(), - path.to_string_lossy().to_string(), - ]); - } - - if config.max_database_cache_size != DEFAULT_CACHE_SIZE { - args.push("--max-database-cache-size".to_string()); - args.push(config.max_database_cache_size.to_string()); - } - - if config.utxo_validation { - args.push("--utxo-validation".to_string()); - } - - if config.manual_blocks_enabled { - args.push("--manual_blocks_enabled".to_string()); - } - - match config.block_production { - Trigger::Instant => { - args.push("--poa-instant=true".to_string()); - } - Trigger::Never => { - args.push("--poa-instant=false".to_string()); - } - Trigger::Interval { block_time } => { - args.push(format!( - "--poa-interval-period={}ms", - block_time.as_millis() - )); - } - Trigger::Hybrid { - min_block_time, - max_tx_idle_time, - max_block_time, - } => { - args.push(format!( - "--poa-hybrid-min-time={}ms", - min_block_time.as_millis() - )); - args.push(format!( - "--poa-hybrid-idle-time={}ms", - max_tx_idle_time.as_millis() - )); - args.push(format!( - "--poa-hybrid-max-time={}ms", - max_block_time.as_millis() - )); - } - }; - - if config.vm_backtrace { - args.push("--vm-backtrace".to_string()); - } - - // Warn if there is more than one binary in PATH. - let binary_name = "fuel-core"; - let paths = which::which_all(binary_name) - .unwrap_or_else(|_| panic!("failed to list '{binary_name}' binaries")) - .collect::>(); - let path = paths - .first() - .unwrap_or_else(|| panic!("no '{binary_name}' in PATH")); - if paths.len() > 1 { - eprintln!( - "found more than one '{}' binary in PATH, using '{}'", - binary_name, - path.display() - ); - } - - let mut command = Command::new(path); - command.stdin(Stdio::null()); - if config.silent { - command.stdout(Stdio::null()).stderr(Stdio::null()); - } - let running_node = command.args(args).kill_on_drop(true).env_clear().output(); - - let client = FuelClient::from(config.addr); - server_health_check(&client).await; - // Sending single to RX to inform that the fuel core node is ready. - tx.send(()).unwrap(); - - let result = running_node - .await - .expect("error: Couldn't find fuel-core in PATH."); - let stdout = String::from_utf8_lossy(&result.stdout); - let stderr = String::from_utf8_lossy(&result.stderr); - eprintln!("the exit status from the fuel binary was: {result:?}, stdout: {stdout}, stderr: {stderr}"); - }); - // Awaiting a signal from Tx that informs us if the fuel-core node is ready. - rx.await.unwrap(); -} - -pub async fn server_health_check(client: &FuelClient) { - let mut attempts = 5; - let mut healthy = client.health().await.unwrap_or(false); - let between_attempts = Duration::from_millis(300); - - while attempts > 0 && !healthy { - healthy = client.health().await.unwrap_or(false); - tokio::time::sleep(between_attempts).await; - attempts -= 1; - } - - if !healthy { - panic!("error: Could not connect to fuel core server.") - } -} - -pub fn get_socket_address() -> SocketAddr { - let free_port = pick_unused_port().expect("No ports free"); - SocketAddr::new("127.0.0.1".parse().unwrap(), free_port) -} - -pub struct FuelService { - pub bound_address: SocketAddr, -} - -impl FuelService { - pub async fn new_node(config: Config) -> Result { - let requested_port = config.addr.port(); - - let bound_address = if requested_port == 0 { - get_socket_address() - } else if is_free(requested_port) { - config.addr - } else { - return Err(error!(InfrastructureError, "Error: Address already in use")); - }; - - new_fuel_node( - vec![], - vec![], - Config { - addr: bound_address, - ..config - }, - None, - ) - .await; - - Ok(FuelService { bound_address }) - } -} diff --git a/packages/fuels-test-helpers/src/node_types.rs b/packages/fuels-test-helpers/src/node_types.rs new file mode 100644 index 00000000..d26bb8ba --- /dev/null +++ b/packages/fuels-test-helpers/src/node_types.rs @@ -0,0 +1,232 @@ +use std::{ + fmt, + net::{Ipv4Addr, SocketAddr}, + path::PathBuf, + time::Duration, +}; + +pub use fuel_core_chain_config::ChainConfig; + +use fuel_types::{BlockHeight, Word}; +use fuels_core::constants::WORD_SIZE; + +use serde::{de::Error as SerdeError, Deserializer, Serializer}; + +use serde_with::{DeserializeAs, SerializeAs}; + +#[derive(Clone, Debug)] +pub enum Trigger { + Instant, + Never, + Interval { + block_time: Duration, + }, + Hybrid { + min_block_time: Duration, + max_tx_idle_time: Duration, + max_block_time: Duration, + }, +} + +#[cfg(feature = "fuel-core-lib")] +impl From for fuel_core_poa::Trigger { + fn from(value: Trigger) -> Self { + match value { + Trigger::Instant => fuel_core_poa::Trigger::Instant, + Trigger::Never => fuel_core_poa::Trigger::Never, + Trigger::Interval { block_time } => fuel_core_poa::Trigger::Interval { block_time }, + _ => value.into(), + } + } +} + +#[derive(Clone, Debug)] +pub enum DbType { + InMemory, + RocksDb(Option), +} + +#[cfg(feature = "fuel-core-lib")] +impl From for fuel_core::service::DbType { + fn from(value: DbType) -> Self { + match value { + DbType::InMemory => fuel_core::service::DbType::InMemory, + DbType::RocksDb(..) => fuel_core::service::DbType::RocksDb, + } + } +} + +#[derive(Clone, Debug)] +pub struct Config { + pub addr: SocketAddr, + pub max_database_cache_size: Option, + pub database_type: DbType, + pub utxo_validation: bool, + pub manual_blocks_enabled: bool, + pub block_production: Trigger, + pub vm_backtrace: bool, + pub silent: bool, + pub chain_conf: ChainConfig, +} + +impl Config { + pub fn local_node() -> Self { + Self { + addr: SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 0), + max_database_cache_size: Some(10 * 1024 * 1024), + database_type: DbType::InMemory, + utxo_validation: false, + manual_blocks_enabled: false, + block_production: Trigger::Instant, + vm_backtrace: false, + silent: true, + chain_conf: ChainConfig::local_testnet(), + } + } +} + +impl Default for Config { + fn default() -> Self { + Self { + addr: SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 0), + max_database_cache_size: Some(10 * 1024 * 1024), + database_type: DbType::InMemory, + utxo_validation: false, + manual_blocks_enabled: false, + block_production: Trigger::Instant, + vm_backtrace: false, + silent: true, + chain_conf: ChainConfig::local_testnet(), + } + } +} + +#[cfg(feature = "fuel-core-lib")] +impl From for fuel_core::service::Config { + fn from(value: Config) -> Self { + Self { + addr: value.addr, + max_database_cache_size: value.max_database_cache_size.unwrap_or(10 * 1024 * 1024), + database_path: match &value.database_type { + DbType::InMemory => Default::default(), + DbType::RocksDb(path) => path.clone().unwrap_or_default(), + }, + database_type: value.database_type.into(), + utxo_validation: value.utxo_validation, + manual_blocks_enabled: value.manual_blocks_enabled, + block_production: value.block_production.into(), + chain_conf: value.chain_conf, + ..fuel_core::service::Config::local_node() + } + } +} + +pub(crate) struct HexType; + +impl> SerializeAs for HexType { + fn serialize_as(value: &T, serializer: S) -> Result + where + S: Serializer, + { + serde_hex::serialize(value, serializer) + } +} + +impl<'de, T, E> DeserializeAs<'de, T> for HexType +where + for<'a> T: TryFrom<&'a [u8], Error = E>, + E: fmt::Display, +{ + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + serde_hex::deserialize(deserializer) + } +} + +pub(crate) mod serde_hex { + use std::{convert::TryFrom, fmt}; + + use hex::{FromHex, ToHex}; + use serde::{de::Error, Deserializer, Serializer}; + + pub fn serialize(target: T, ser: S) -> Result + where + S: Serializer, + T: ToHex, + { + let s = format!("0x{}", target.encode_hex::()); + ser.serialize_str(&s) + } + + pub fn deserialize<'de, T, E, D>(des: D) -> Result + where + D: Deserializer<'de>, + for<'a> T: TryFrom<&'a [u8], Error = E>, + E: fmt::Display, + { + let raw_string: String = serde::Deserialize::deserialize(des)?; + let stripped_prefix = raw_string.trim_start_matches("0x"); + let bytes: Vec = FromHex::from_hex(stripped_prefix).map_err(D::Error::custom)?; + let result = T::try_from(bytes.as_slice()).map_err(D::Error::custom)?; + Ok(result) + } +} + +pub(crate) struct HexNumber; + +impl SerializeAs for HexNumber { + fn serialize_as(value: &u64, serializer: S) -> Result + where + S: Serializer, + { + let bytes = value.to_be_bytes(); + serde_hex::serialize(bytes, serializer) + } +} + +impl<'de> DeserializeAs<'de, Word> for HexNumber { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let mut bytes: Vec = serde_hex::deserialize(deserializer)?; + match bytes.len() { + len if len > WORD_SIZE => { + return Err(D::Error::custom(format!( + "value can't exceed {WORD_SIZE} bytes", + ))); + } + len if len < WORD_SIZE => { + // pad if length < word size + bytes = (0..WORD_SIZE - len).map(|_| 0u8).chain(bytes).collect(); + } + _ => {} + } + // We've already verified the bytes.len == WORD_SIZE, force the conversion here. + Ok(Word::from_be_bytes( + bytes.try_into().expect("byte lengths checked"), + )) + } +} + +impl SerializeAs for HexNumber { + fn serialize_as(value: &BlockHeight, serializer: S) -> Result + where + S: Serializer, + { + let number = u32::from(*value) as u64; + HexNumber::serialize_as(&number, serializer) + } +} + +impl<'de> DeserializeAs<'de, BlockHeight> for HexNumber { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let number: u64 = HexNumber::deserialize_as(deserializer)?; + Ok((number as u32).into()) + } +} diff --git a/packages/fuels-test-helpers/src/service.rs b/packages/fuels-test-helpers/src/service.rs new file mode 100644 index 00000000..e5357ab4 --- /dev/null +++ b/packages/fuels-test-helpers/src/service.rs @@ -0,0 +1,56 @@ +use crate::Config; +use fuels_core::types::errors::{error, Error, Result}; +use std::net::SocketAddr; + +use fuel_core_services::State; + +#[cfg(feature = "fuel-core-lib")] +use fuel_core::service::FuelService as CoreFuelService; +#[cfg(feature = "fuel-core-lib")] +use fuel_core_services::Service; + +#[cfg(not(feature = "fuel-core-lib"))] +use crate::fuel_bin_service::FuelService as BinFuelService; + +pub struct FuelService { + #[cfg(feature = "fuel-core-lib")] + service: CoreFuelService, + #[cfg(not(feature = "fuel-core-lib"))] + service: BinFuelService, + bound_address: SocketAddr, +} + +impl FuelService { + pub async fn start(config: Config) -> Result { + #[cfg(feature = "fuel-core-lib")] + let service = CoreFuelService::new_node(config.into()) + .await + .map_err(|err| error!(InfrastructureError, "{}", err))?; + + #[cfg(not(feature = "fuel-core-lib"))] + let service = BinFuelService::new_node(config) + .await + .map_err(|err| error!(InfrastructureError, "{}", err))?; + + let bound_address = service.bound_address; + + Ok(FuelService { + service, + bound_address, + }) + } + + pub async fn stop(&self) -> Result { + #[cfg(feature = "fuel-core-lib")] + let result = self.service.stop_and_await().await; + + #[cfg(not(feature = "fuel-core-lib"))] + let result = self.service.stop(); + + result.map_err(|err| error!(InfrastructureError, "{}", err)) + } + + pub fn bound_address(&self) -> SocketAddr { + self.bound_address + } +} diff --git a/packages/fuels-test-helpers/src/utils.rs b/packages/fuels-test-helpers/src/utils.rs index 799ca1fa..d459f633 100644 --- a/packages/fuels-test-helpers/src/utils.rs +++ b/packages/fuels-test-helpers/src/utils.rs @@ -1,14 +1,14 @@ use fuel_core_chain_config::{CoinConfig, MessageConfig}; use fuels_core::types::{coin::Coin, message::Message}; -pub fn into_coin_configs(coins: Vec) -> Vec { +pub(crate) fn into_coin_configs(coins: Vec) -> Vec { coins .into_iter() .map(Into::into) .collect::>() } -pub fn into_message_configs(messages: Vec) -> Vec { +pub(crate) fn into_message_configs(messages: Vec) -> Vec { messages .into_iter() .map(Into::into) diff --git a/packages/fuels/Cargo.toml b/packages/fuels/Cargo.toml index 94a67e28..50088c01 100644 --- a/packages/fuels/Cargo.toml +++ b/packages/fuels/Cargo.toml @@ -10,6 +10,9 @@ repository = { workspace = true } rust-version = { workspace = true } description = "Fuel Rust SDK." +[package.metadata.cargo-machete] +ignored = ["fuel-core"] + [dependencies] fuel-core = { workspace = true, default-features = false, optional = true } fuel-core-client = { workspace = true, optional = true } @@ -25,6 +28,7 @@ fuels-code-gen = { workspace = true } chrono = { workspace = true } fuel-core = { workspace = true, default-features = false } fuel-core-types = { workspace = true } +fuels-test-helpers = { workspace = true } hex = { workspace = true, default-features = false } sha2 = { workspace = true } tempfile = { workspace = true } diff --git a/packages/fuels/src/lib.rs b/packages/fuels/src/lib.rs index 2c867c0a..8f7a9f00 100644 --- a/packages/fuels/src/lib.rs +++ b/packages/fuels/src/lib.rs @@ -54,16 +54,6 @@ pub mod test_helpers { pub use fuels_test_helpers::*; } -#[cfg(feature = "std")] -pub mod fuel_node { - #[cfg(feature = "fuel-core-lib")] - pub use fuel_core::chain_config::ChainConfig; - #[cfg(feature = "fuel-core-lib")] - pub use fuel_core::service::{config::Trigger, Config, DbType, FuelService}; - #[cfg(not(feature = "fuel-core-lib"))] - pub use fuels_test_helpers::node::{ChainConfig, Config, DbType, FuelService, Trigger}; -} - /// Easy imports of frequently used #[doc(hidden)] pub mod prelude { @@ -83,7 +73,6 @@ pub mod prelude { Account, Signer, ViewOnlyAccount, }, core::codec::{LogDecoder, LogId, LogResult}, - fuel_node::*, programs::{ call_utils::TxDependencyExtension, contract::{ diff --git a/packages/fuels/tests/bindings.rs b/packages/fuels/tests/bindings.rs index ea28c82d..4623241f 100644 --- a/packages/fuels/tests/bindings.rs +++ b/packages/fuels/tests/bindings.rs @@ -87,7 +87,7 @@ async fn compile_bindings_from_inline_contract() -> Result<()> { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -105,7 +105,7 @@ async fn compile_bindings_from_inline_contract() -> Result<()> { } #[tokio::test] -async fn compile_bindings_array_input() { +async fn compile_bindings_array_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -159,7 +159,7 @@ async fn compile_bindings_array_input() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -177,10 +177,12 @@ async fn compile_bindings_array_input() { "00000000101cbeb5000000000000000100000000000000020000000000000003", encoded ); + + Ok(()) } #[tokio::test] -async fn compile_bindings_bool_array_input() { +async fn compile_bindings_bool_array_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -234,7 +236,7 @@ async fn compile_bindings_bool_array_input() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -252,10 +254,12 @@ async fn compile_bindings_bool_array_input() { "000000000c228226000000000000000100000000000000000000000000000001", encoded ); + + Ok(()) } #[tokio::test] -async fn compile_bindings_string_input() { +async fn compile_bindings_string_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -297,7 +301,7 @@ async fn compile_bindings_string_input() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -320,10 +324,12 @@ async fn compile_bindings_string_input() { "00000000d56e76515468697320697320612066756c6c2073656e74656e636500", encoded ); + + Ok(()) } #[tokio::test] -async fn compile_bindings_b256_input() { +async fn compile_bindings_b256_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -365,7 +371,7 @@ async fn compile_bindings_b256_input() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -389,10 +395,12 @@ async fn compile_bindings_b256_input() { "0000000054992852d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b", encoded ); + + Ok(()) } #[tokio::test] -async fn compile_bindings_evm_address_input() { +async fn compile_bindings_evm_address_input() -> Result<()> { abigen!(Contract( name = "SimpleContract", abi = r#" @@ -432,7 +440,7 @@ async fn compile_bindings_evm_address_input() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -457,10 +465,12 @@ async fn compile_bindings_evm_address_input() { "000000006ef3f9a50000000000000000000000005b44e4cb4e2c2298f4ac457ba8f82743f31e930b", encoded ); + + Ok(()) } #[tokio::test] -async fn compile_bindings_struct_input() { +async fn compile_bindings_struct_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -543,7 +553,7 @@ async fn compile_bindings_struct_input() { bar: "fuel".try_into().unwrap(), }; - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -560,10 +570,12 @@ async fn compile_bindings_struct_input() { "000000008d4ab9b0000000000000000a00000000000000026675656c00000000", encoded ); + + Ok(()) } #[tokio::test] -async fn compile_bindings_nested_struct_input() { +async fn compile_bindings_nested_struct_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -647,7 +659,7 @@ async fn compile_bindings_nested_struct_input() { foo: inner_struct, }; - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -665,10 +677,12 @@ async fn compile_bindings_nested_struct_input() { ); assert_eq!("0000000088bf8a1b000000000000000a0000000000000001", encoded); + + Ok(()) } #[tokio::test] -async fn compile_bindings_enum_input() { +async fn compile_bindings_enum_input() -> Result<()> { // Generates the bindings from the an ABI definition inline. // The generated bindings can be accessed through `SimpleContract`. abigen!(Contract( @@ -735,7 +749,7 @@ async fn compile_bindings_enum_input() { let variant = MyEnum::X(42); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -750,6 +764,8 @@ async fn compile_bindings_enum_input() { let expected = "0000000021b2784f0000000000000000000000000000002a"; assert_eq!(encoded, expected); + + Ok(()) } #[tokio::test] diff --git a/packages/fuels/tests/configurables.rs b/packages/fuels/tests/configurables.rs index 246fe226..a402e774 100644 --- a/packages/fuels/tests/configurables.rs +++ b/packages/fuels/tests/configurables.rs @@ -7,7 +7,7 @@ async fn contract_uses_default_configurables() -> Result<()> { abi = "packages/fuels/tests/contracts/configurables/out/debug/configurables-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "tests/contracts/configurables/out/debug/configurables.bin", @@ -83,7 +83,7 @@ async fn contract_configurables() -> Result<()> { abi = "packages/fuels/tests/contracts/configurables/out/debug/configurables-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let new_str: SizedAsciiString<4> = "FUEL".try_into()?; let new_struct = StructWithGeneric { @@ -132,7 +132,7 @@ async fn script_configurables() -> Result<()> { // ANCHOR: script_configurables abigen!(Script(name="MyScript", abi="packages/fuels/tests/scripts/script_configurables/out/debug/script_configurables-abi.json")); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let bin_path = "../fuels/tests/scripts/script_configurables/out/debug/script_configurables.bin"; let instance = MyScript::new(wallet, bin_path); diff --git a/packages/fuels/tests/contracts.rs b/packages/fuels/tests/contracts.rs index f1f4f83c..bd6c8b4f 100644 --- a/packages/fuels/tests/contracts.rs +++ b/packages/fuels/tests/contracts.rs @@ -2,7 +2,6 @@ use std::future::Future; use std::vec; -use fuel_core::chain_config::ChainConfig; use fuels::{ accounts::{predicate::Predicate, Account}, core::codec::{calldata, fn_selector}, @@ -601,7 +600,7 @@ async fn test_connect_wallet() -> Result<()> { // ANCHOR: contract_setup_macro_manual_wallet let config = WalletsConfig::new(Some(2), Some(1), Some(DEFAULT_COIN_AMOUNT)); - let mut wallets = launch_custom_provider_and_get_wallets(config, None, None).await; + let mut wallets = launch_custom_provider_and_get_wallets(config, None, None).await?; let wallet = wallets.pop().unwrap(); let wallet_2 = wallets.pop().unwrap(); @@ -653,7 +652,7 @@ async fn test_connect_wallet() -> Result<()> { async fn setup_output_variable_estimation_test( ) -> Result<(Vec, [Address; 3], AssetId, Bech32ContractId)> { let wallet_config = WalletsConfig::new(Some(3), None, None); - let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await?; let contract_id = Contract::load_from( "tests/contracts/token_ops/out/debug/token_ops.bin", @@ -816,7 +815,7 @@ async fn test_contract_instance_get_balances() -> Result<()> { let (coins, asset_ids) = setup_multiple_assets_coins(wallet.address(), 2, 4, 8); let random_asset_id = &asset_ids[1]; - let provider = setup_test_provider(coins.clone(), vec![], None, None).await; + let provider = setup_test_provider(coins.clone(), vec![], None, None).await?; wallet.set_provider(provider.clone()); setup_program_test!( @@ -1025,7 +1024,7 @@ async fn test_contract_call_with_non_default_max_input() -> Result<()> { ..ChainConfig::default() }; - let provider = setup_test_provider(coins, vec![], None, Some(chain_config)).await; + let provider = setup_test_provider(coins, vec![], None, Some(chain_config)).await?; wallet.set_provider(provider.clone()); assert_eq!(consensus_parameters_config, provider.consensus_parameters()); @@ -1075,7 +1074,7 @@ async fn test_add_custom_assets() -> Result<()> { let num_wallets = 2; let wallet_config = WalletsConfig::new_multiple_assets(num_wallets, assets); - let mut wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await; + let mut wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await?; let wallet_1 = wallets.pop().unwrap(); let wallet_2 = wallets.pop().unwrap(); @@ -1330,7 +1329,7 @@ fn db_rocksdb() { use fuels::{ accounts::{fuel_crypto::SecretKey, wallet::WalletUnlocked}, client::{PageDirection, PaginationRequest}, - prelude::{setup_test_provider, Config, DbType, ViewOnlyAccount, DEFAULT_COIN_AMOUNT}, + prelude::{setup_test_provider, DbType, ViewOnlyAccount, DEFAULT_COIN_AMOUNT}, }; let temp_dir = tempfile::tempdir() @@ -1355,10 +1354,8 @@ fn db_rocksdb() { ); const NUMBER_OF_ASSETS: u64 = 2; - let mut node_config = Config { - database_path: temp_database_path.clone(), - database_type: DbType::RocksDb, + database_type: DbType::RocksDb(Some(temp_database_path.clone())), ..Config::local_node() }; @@ -1380,7 +1377,7 @@ fn db_rocksdb() { let provider = setup_test_provider(coins.clone(), vec![], Some(node_config), Some(chain_config)) - .await; + .await?; provider.produce_blocks(2, None).await?; @@ -1394,12 +1391,11 @@ fn db_rocksdb() { .expect("Tokio runtime failed") .block_on(async { let node_config = Config { - database_path: temp_database_path.clone(), - database_type: DbType::RocksDb, + database_type: DbType::RocksDb(Some(temp_database_path.clone())), ..Config::local_node() }; - let provider = setup_test_provider(vec![], vec![], Some(node_config), None).await; + let provider = setup_test_provider(vec![], vec![], Some(node_config), None).await?; // the same wallet that was used when rocksdb was built. When we connect it to the provider, we expect it to have the same amount of assets let mut wallet = WalletUnlocked::new_from_private_key( SecretKey::from_str( diff --git a/packages/fuels/tests/from_token.rs b/packages/fuels/tests/from_token.rs index c0b342bd..7ea35047 100644 --- a/packages/fuels/tests/from_token.rs +++ b/packages/fuels/tests/from_token.rs @@ -85,7 +85,7 @@ async fn create_struct_from_decoded_tokens() -> Result<()> { assert_eq!(10, struct_from_tokens.foo); assert!(struct_from_tokens.bar); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); @@ -198,7 +198,7 @@ async fn create_nested_struct_from_decoded_tokens() -> Result<()> { assert_eq!(10, nested_struct_from_tokens.x); assert!(nested_struct_from_tokens.foo.a); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_instance = SimpleContract::new(null_contract_id(), wallet); diff --git a/packages/fuels/tests/logs.rs b/packages/fuels/tests/logs.rs index a02a9d60..0a92a9d1 100644 --- a/packages/fuels/tests/logs.rs +++ b/packages/fuels/tests/logs.rs @@ -617,7 +617,7 @@ async fn test_script_decode_logs() -> Result<()> { abi = "packages/fuels/tests/logs/script_logs/out/debug/script_logs-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let bin_path = "../fuels/tests/logs/script_logs/out/debug/script_logs.bin"; let instance = log_script::new(wallet.clone(), bin_path); diff --git a/packages/fuels/tests/predicates.rs b/packages/fuels/tests/predicates.rs index bfe1fe2f..289d9741 100644 --- a/packages/fuels/tests/predicates.rs +++ b/packages/fuels/tests/predicates.rs @@ -93,7 +93,7 @@ async fn setup_predicate_test( manual_blocks_enabled: true, ..Config::local_node() }; - let provider = setup_test_provider(coins, messages, Some(config), None).await; + let provider = setup_test_provider(coins, messages, Some(config), None).await?; receiver.set_provider(provider.clone()); Ok(( @@ -117,7 +117,7 @@ async fn transfer_coins_and_messages_to_predicate() -> Result<()> { let (coins, messages, asset_id) = get_test_coins_and_messages(wallet.address(), num_coins, num_messages, amount, 0); - let provider = setup_test_provider(coins, messages, None, None).await; + let provider = setup_test_provider(coins, messages, None, None).await?; wallet.set_provider(provider.clone()); @@ -443,7 +443,7 @@ async fn predicate_transfer_with_signed_resources() -> Result<()> { coins.extend(wallet_coins); messages.extend(wallet_messages); - let provider = setup_test_provider(coins, messages, None, None).await; + let provider = setup_test_provider(coins, messages, None, None).await?; wallet.set_provider(provider.clone()); predicate.set_provider(provider.clone()); @@ -692,7 +692,7 @@ async fn predicate_add_fee_persists_message_w_data() -> Result<()> { predicate.data().clone(), ); - let provider = setup_test_provider(coins, vec![message.clone()], None, None).await; + let provider = setup_test_provider(coins, vec![message.clone()], None, None).await?; predicate.set_provider(provider.clone()); let network_info = provider.network_info().await?; @@ -737,7 +737,7 @@ async fn predicate_transfer_non_base_asset() -> Result<()> { amount, )); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; predicate.set_provider(provider.clone()); wallet.set_provider(provider.clone()); diff --git a/packages/fuels/tests/providers.rs b/packages/fuels/tests/providers.rs index d94497bd..baf95931 100644 --- a/packages/fuels/tests/providers.rs +++ b/packages/fuels/tests/providers.rs @@ -1,7 +1,7 @@ use std::{iter, ops::Add, str::FromStr, vec}; use chrono::{DateTime, Duration, NaiveDateTime, TimeZone, Utc}; -use fuel_core::service::{Config as CoreConfig, FuelService, ServiceTrait}; + use fuel_core_types::{ fuel_crypto::rand::{self, Rng}, tai64::Tai64, @@ -10,9 +10,8 @@ use fuels::{ accounts::{fuel_crypto::SecretKey, Account}, client::{PageDirection, PaginationRequest}, prelude::*, - test_helpers::Config, tx::Receipt, - types::{block::Block, coin_type::CoinType, errors::error, message::Message}, + types::{block::Block, coin_type::CoinType, message::Message}, }; use fuels_core::types::{ transaction_builders::{ScriptTransactionBuilder, TransactionBuilder}, @@ -34,7 +33,7 @@ async fn test_provider_launch_and_connect() -> Result<()> { DEFAULT_NUM_COINS, DEFAULT_COIN_AMOUNT, ); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; wallet.set_provider(provider.clone()); let contract_id = Contract::load_from( @@ -74,16 +73,14 @@ async fn test_network_error() -> Result<()> { let mut wallet = WalletUnlocked::new_random(None); - let config = CoreConfig::local_node(); - let service = FuelService::new_node(config) - .await - .map_err(|err| error!(InfrastructureError, "{err}"))?; - let provider = Provider::connect(service.bound_address.to_string()).await?; + let config = Config::local_node(); + let service = FuelService::start(config).await?; + let provider = Provider::connect(service.bound_address().to_string()).await?; wallet.set_provider(provider); // Simulate an unreachable node - service.stop_and_await().await.unwrap(); + service.stop().await.unwrap(); let response = Contract::load_from( "tests/contracts/contract_test/out/debug/contract_test.bin", @@ -121,7 +118,7 @@ async fn test_input_message() -> Result<()> { vec![1, 2], )]; - let provider = setup_test_provider(coins, messages.clone(), None, None).await; + let provider = setup_test_provider(coins, messages.clone(), None, None).await?; wallet.set_provider(provider); setup_program_test!( @@ -165,7 +162,7 @@ async fn test_input_message_pays_fee() -> Result<()> { vec![], ); - let provider = setup_test_provider(vec![], vec![messages], None, None).await; + let provider = setup_test_provider(vec![], vec![messages], None, None).await?; wallet.set_provider(provider); abigen!(Contract( @@ -205,7 +202,8 @@ async fn can_increase_block_height() -> Result<()> { ..Config::local_node() }; let wallets = - launch_custom_provider_and_get_wallets(WalletsConfig::default(), Some(config), None).await; + launch_custom_provider_and_get_wallets(WalletsConfig::default(), Some(config), None) + .await?; let wallet = &wallets[0]; let provider = wallet.try_provider()?; @@ -231,7 +229,8 @@ async fn can_set_custom_block_time() -> Result<()> { ..Config::local_node() }; let wallets = - launch_custom_provider_and_get_wallets(WalletsConfig::default(), Some(config), None).await; + launch_custom_provider_and_get_wallets(WalletsConfig::default(), Some(config), None) + .await?; let wallet = &wallets[0]; let provider = wallet.try_provider()?; @@ -267,7 +266,7 @@ async fn can_set_custom_block_time() -> Result<()> { #[tokio::test] async fn can_retrieve_latest_block_time() -> Result<()> { - let provider = given_a_provider().await; + let provider = given_a_provider().await?; let since_epoch = 1676039910; let latest_timestamp = Utc.timestamp_opt(since_epoch, 0).unwrap(); @@ -281,7 +280,7 @@ async fn can_retrieve_latest_block_time() -> Result<()> { Ok(()) } -async fn given_a_provider() -> Provider { +async fn given_a_provider() -> Result { let config = Config { manual_blocks_enabled: true, // Necessary so the `produce_blocks` API can be used locally ..Config::local_node() @@ -298,7 +297,8 @@ async fn contract_deployment_respects_maturity() -> Result<()> { ..Config::local_node() }; let wallets = - launch_custom_provider_and_get_wallets(WalletsConfig::default(), Some(config), None).await; + launch_custom_provider_and_get_wallets(WalletsConfig::default(), Some(config), None) + .await?; let wallet = &wallets[0]; let provider = wallet.try_provider()?; @@ -327,7 +327,7 @@ async fn contract_deployment_respects_maturity() -> Result<()> { #[tokio::test] async fn test_default_tx_params_match_network() -> Result<()> { - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let provider = wallet.try_provider()?; let consensus_params = provider.consensus_parameters(); @@ -497,7 +497,7 @@ async fn test_gas_errors() -> Result<()> { amount_per_coin, ); - let provider = setup_test_provider(coins.clone(), vec![], None, None).await; + let provider = setup_test_provider(coins.clone(), vec![], None, None).await?; wallet.set_provider(provider); setup_program_test!( @@ -684,7 +684,7 @@ async fn testnet_hello_world() -> Result<()> { async fn test_parse_block_time() -> Result<()> { let mut wallet = WalletUnlocked::new_random(None); let coins = setup_single_asset_coins(wallet.address(), AssetId::BASE, 1, DEFAULT_COIN_AMOUNT); - let provider = setup_test_provider(coins.clone(), vec![], None, None).await; + let provider = setup_test_provider(coins.clone(), vec![], None, None).await?; wallet.set_provider(provider); let tx_parameters = TxParameters::default() .with_gas_price(1) @@ -735,7 +735,7 @@ async fn test_get_spendable_with_exclusion() -> Result<()> { let message_nonce = message.nonce; - let provider = setup_test_provider(coins, vec![message], None, None).await; + let provider = setup_test_provider(coins, vec![message], None, None).await?; wallet.set_provider(provider.clone()); @@ -807,7 +807,7 @@ async fn test_sway_timestamp() -> Result<()> { Some(provider_config), None, ) - .await; + .await?; let wallet = wallets.pop().unwrap(); let provider = wallet.try_provider()?; diff --git a/packages/fuels/tests/scripts.rs b/packages/fuels/tests/scripts.rs index c4f58b50..3f1f021e 100644 --- a/packages/fuels/tests/scripts.rs +++ b/packages/fuels/tests/scripts.rs @@ -65,7 +65,7 @@ async fn main_function_arguments() -> Result<()> { name = "MyScript", abi = "packages/fuels/tests/scripts/arguments/out/debug/arguments-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let bin_path = "../fuels/tests/scripts/arguments/out/debug/arguments.bin"; let script_instance = MyScript::new(wallet, bin_path); @@ -150,7 +150,7 @@ async fn test_basic_script_with_tx_parameters() -> Result<()> { #[tokio::test] async fn test_script_call_with_non_default_max_input() -> Result<()> { - use fuels::{tx::ConsensusParameters, types::coin::Coin}; + use fuels::{test_helpers::ChainConfig, tx::ConsensusParameters, types::coin::Coin}; let consensus_parameters_config = ConsensusParameters::DEFAULT.with_max_inputs(128); let chain_config = ChainConfig { @@ -167,7 +167,7 @@ async fn test_script_call_with_non_default_max_input() -> Result<()> { DEFAULT_COIN_AMOUNT, ); - let provider = setup_test_provider(coins, vec![], None, Some(chain_config)).await; + let provider = setup_test_provider(coins, vec![], None, Some(chain_config)).await?; assert_eq!(provider.consensus_parameters(), consensus_parameters_config); wallet.set_provider(provider.clone()); @@ -201,7 +201,7 @@ async fn test_script_signing() -> Result<()> { }; let wallets = - launch_custom_provider_and_get_wallets(wallet_config, Some(provider_config), None).await; + launch_custom_provider_and_get_wallets(wallet_config, Some(provider_config), None).await?; let wallet = wallets.first().unwrap(); setup_program_test!( diff --git a/packages/fuels/tests/storage.rs b/packages/fuels/tests/storage.rs index fef23a74..8f6d88fc 100644 --- a/packages/fuels/tests/storage.rs +++ b/packages/fuels/tests/storage.rs @@ -13,7 +13,7 @@ async fn test_storage_initialization() -> Result<()> { abi = "packages/fuels/tests/contracts/storage/out/debug/storage-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let key = Bytes32::from([1u8; 32]); let value = Bytes32::from([2u8; 32]); @@ -48,7 +48,7 @@ async fn test_init_storage_automatically() -> Result<()> { abi = "packages/fuels/tests/contracts/storage/out/debug/storage-abi.json" )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "tests/contracts/storage/out/debug/storage.bin", diff --git a/packages/fuels/tests/types_contracts.rs b/packages/fuels/tests/types_contracts.rs index 2d8080ee..9e51e71a 100644 --- a/packages/fuels/tests/types_contracts.rs +++ b/packages/fuels/tests/types_contracts.rs @@ -71,7 +71,7 @@ async fn call_with_structs() -> Result<()> { }; // ANCHOR_END: struct_generation - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let contract_id = Contract::load_from( "tests/types/contracts/complex_types_contract/out/debug/complex_types_contract.bin", @@ -832,7 +832,9 @@ async fn strings_must_have_correct_length() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet() + .await + .expect("Should have wallet"); let contract_instance = SimpleContract::new(null_contract_id(), wallet); let _ = contract_instance .methods() @@ -883,7 +885,7 @@ async fn strings_must_have_all_ascii_chars() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await.unwrap(); let contract_instance = SimpleContract::new(null_contract_id(), wallet); let _ = contract_instance .methods() @@ -969,7 +971,7 @@ async fn strings_must_have_correct_length_custom_types() { "#, )); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await.unwrap(); let contract_instance = SimpleContract::new(null_contract_id(), wallet); let _ = contract_instance .methods() @@ -1063,7 +1065,9 @@ async fn strings_must_have_all_ascii_chars_custom_types() { foo: inner_struct, }; - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet() + .await + .expect("Should have wallet"); let contract_instance = SimpleContract::new(null_contract_id(), wallet); let _ = contract_instance.methods().takes_nested_struct(input); } @@ -1948,7 +1952,7 @@ async fn test_bytes_as_input() -> Result<()> { #[tokio::test] async fn test_contract_raw_slice() -> Result<()> { - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; setup_program_test!( Abigen(Contract( name = "RawSliceContract", @@ -1993,7 +1997,7 @@ async fn test_contract_raw_slice() -> Result<()> { #[tokio::test] async fn test_contract_returning_string_slice() -> Result<()> { - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; setup_program_test!( Abigen(Contract( name = "StringSliceContract", @@ -2018,7 +2022,7 @@ async fn test_contract_returning_string_slice() -> Result<()> { #[tokio::test] async fn test_contract_std_lib_string() -> Result<()> { - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; setup_program_test!( Abigen(Contract( name = "StdLibString", @@ -2048,7 +2052,7 @@ async fn test_contract_std_lib_string() -> Result<()> { #[tokio::test] async fn test_heap_type_in_enums() -> Result<()> { - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; setup_program_test!( Abigen(Contract( name = "HeapTypeInEnum", diff --git a/packages/fuels/tests/types_predicates.rs b/packages/fuels/tests/types_predicates.rs index d3b1bb16..7909f9dc 100644 --- a/packages/fuels/tests/types_predicates.rs +++ b/packages/fuels/tests/types_predicates.rs @@ -113,7 +113,7 @@ async fn setup_predicate_test( receiver_amount, )); - let provider = setup_test_provider(coins, messages, None, None).await; + let provider = setup_test_provider(coins, messages, None, None).await?; receiver.set_provider(provider.clone()); Ok(( diff --git a/packages/fuels/tests/types_scripts.rs b/packages/fuels/tests/types_scripts.rs index 36bd8f58..7e3d5b6f 100644 --- a/packages/fuels/tests/types_scripts.rs +++ b/packages/fuels/tests/types_scripts.rs @@ -77,7 +77,7 @@ async fn main_function_tuple_types() -> Result<()> { wallet = "wallet" ) ); - let wallet = launch_provider_and_get_wallet().await; + let wallet = launch_provider_and_get_wallet().await?; let bin_path = "../fuels/tests/types/scripts/script_tuples/out/debug/script_tuples.bin"; let instance = MyScript::new(wallet, bin_path); diff --git a/packages/fuels/tests/wallets.rs b/packages/fuels/tests/wallets.rs index 897a2377..905d012a 100644 --- a/packages/fuels/tests/wallets.rs +++ b/packages/fuels/tests/wallets.rs @@ -19,7 +19,7 @@ async fn test_wallet_balance_api_multi_asset() -> Result<()> { amount_per_coin, ); - let provider = setup_test_provider(coins.clone(), vec![], None, None).await; + let provider = setup_test_provider(coins.clone(), vec![], None, None).await?; wallet.set_provider(provider); let balances = wallet.get_balances().await?; assert_eq!(balances.len() as u64, number_of_assets); @@ -50,7 +50,7 @@ async fn test_wallet_balance_api_single_asset() -> Result<()> { amount_per_coin, ); - let provider = setup_test_provider(coins.clone(), vec![], None, None).await; + let provider = setup_test_provider(coins.clone(), vec![], None, None).await?; wallet.set_provider(provider); for coin in coins { @@ -133,7 +133,7 @@ fn base_asset_wallet_config(num_wallets: u64) -> WalletsConfig { async fn add_fee_resources_empty_transaction() -> Result<()> { let wallet_config = base_asset_wallet_config(1); let wallet = launch_custom_provider_and_get_wallets(wallet_config, None, None) - .await + .await? .pop() .unwrap(); @@ -168,7 +168,7 @@ async fn add_fee_resources_empty_transaction() -> Result<()> { async fn add_fee_resources_to_transfer_with_base_asset() -> Result<()> { let wallet_config = base_asset_wallet_config(1); let wallet = launch_custom_provider_and_get_wallets(wallet_config, None, None) - .await + .await? .pop() .unwrap(); @@ -223,7 +223,7 @@ async fn test_transfer() -> Result<()> { coins_1.extend(coins_2); // Setup a provider and node with both set of coins - let provider = setup_test_provider(coins_1, vec![], None, None).await; + let provider = setup_test_provider(coins_1, vec![], None, None).await?; // Set provider for wallets wallet_1.set_provider(provider.clone()); @@ -250,7 +250,7 @@ async fn test_transfer() -> Result<()> { #[tokio::test] async fn send_transfer_transactions() -> Result<()> { const AMOUNT: u64 = 5; - let (wallet_1, wallet_2) = setup_transfer_test(AMOUNT).await; + let (wallet_1, wallet_2) = setup_transfer_test(AMOUNT).await?; // Configure transaction parameters. let gas_price = 1; @@ -298,7 +298,7 @@ async fn send_transfer_transactions() -> Result<()> { #[tokio::test] async fn transfer_coins_with_change() -> Result<()> { const AMOUNT: u64 = 5; - let (wallet_1, wallet_2) = setup_transfer_test(AMOUNT).await; + let (wallet_1, wallet_2) = setup_transfer_test(AMOUNT).await?; // Transfer 2 from wallet 1 to wallet 2. const SEND_AMOUNT: u64 = 2; @@ -332,7 +332,7 @@ async fn test_wallet_get_coins() -> Result<()> { let mut wallet = WalletUnlocked::new_random(None); let coins = setup_single_asset_coins(wallet.address(), BASE_ASSET_ID, NUM_COINS, AMOUNT); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; wallet.set_provider(provider.clone()); let wallet_initial_coins = wallet.get_coins(BASE_ASSET_ID).await?; @@ -344,24 +344,24 @@ async fn test_wallet_get_coins() -> Result<()> { Ok(()) } -async fn setup_transfer_test(amount: u64) -> (WalletUnlocked, Wallet) { +async fn setup_transfer_test(amount: u64) -> Result<(WalletUnlocked, Wallet)> { let mut wallet_1 = WalletUnlocked::new_random(None); let mut wallet_2 = WalletUnlocked::new_random(None).lock(); let coins = setup_single_asset_coins(wallet_1.address(), BASE_ASSET_ID, 1, amount); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; wallet_1.set_provider(provider.clone()); wallet_2.set_provider(provider); - (wallet_1, wallet_2) + Ok((wallet_1, wallet_2)) } #[tokio::test] async fn transfer_more_than_owned() -> Result<()> { const AMOUNT: u64 = 1000000; - let (wallet_1, wallet_2) = setup_transfer_test(AMOUNT).await; + let (wallet_1, wallet_2) = setup_transfer_test(AMOUNT).await?; // Transferring more than balance should fail. let response = wallet_1 @@ -391,7 +391,7 @@ async fn transfer_coins_of_non_base_asset() -> Result<()> { let base_coins = setup_single_asset_coins(wallet_1.address(), BASE_ASSET_ID, 1, AMOUNT); coins.extend(base_coins); - let provider = setup_test_provider(coins, vec![], None, None).await; + let provider = setup_test_provider(coins, vec![], None, None).await?; wallet_1.set_provider(provider.clone()); wallet_2.set_provider(provider); @@ -420,7 +420,7 @@ async fn transfer_coins_of_non_base_asset() -> Result<()> { #[tokio::test] async fn test_transfer_with_multiple_signatures() -> Result<()> { let wallet_config = base_asset_wallet_config(5); - let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await; + let wallets = launch_custom_provider_and_get_wallets(wallet_config, None, None).await?; let provider = wallets[0].try_provider()?; let mut receiver = WalletUnlocked::new_random(None);