1extern crate core;
3
4#[cfg(feature = "fuels-accounts")]
5pub use accounts::*;
6use fuel_tx::{Bytes32, ConsensusParameters, ContractParameters, TxParameters, UtxoId};
7use fuel_types::{AssetId, Nonce};
8use fuels_accounts::provider::Provider;
9use fuels_core::types::{
10 Address,
11 coin::Coin,
12 errors::Result,
13 message::{Message, MessageStatus},
14};
15pub use node_types::*;
16use rand::{Fill, Rng, SeedableRng, rngs::StdRng};
17use utils::{into_coin_configs, into_message_configs};
18pub use wallets_config::*;
19mod node_types;
20
21#[cfg(not(feature = "fuel-core-lib"))]
22pub(crate) mod fuel_bin_service;
23
24#[cfg(feature = "fuels-accounts")]
25mod accounts;
26
27pub use service::*;
28mod service;
29
30mod utils;
31mod wallets_config;
32
33pub fn setup_multiple_assets_coins(
39 owner: Address,
40 num_asset: u64,
41 coins_per_asset: u64,
42 amount_per_coin: u64,
43) -> (Vec<Coin>, Vec<AssetId>) {
44 let mut rng = rand::thread_rng();
45 let asset_ids = (0..(num_asset - 1))
47 .map(|_| {
48 let mut random_asset_id = AssetId::zeroed();
49 random_asset_id
50 .try_fill(&mut rng)
51 .expect("failed to fill with random data");
52 random_asset_id
53 })
54 .chain([AssetId::zeroed()])
55 .collect::<Vec<AssetId>>();
56
57 let coins = asset_ids
58 .iter()
59 .flat_map(|id| setup_single_asset_coins(owner, *id, coins_per_asset, amount_per_coin))
60 .collect::<Vec<Coin>>();
61
62 (coins, asset_ids)
63}
64
65pub fn setup_custom_assets_coins(owner: Address, assets: &[AssetConfig]) -> Vec<Coin> {
67 let coins = assets
68 .iter()
69 .flat_map(|asset| {
70 setup_single_asset_coins(owner, asset.id, asset.num_coins, asset.coin_amount)
71 })
72 .collect::<Vec<Coin>>();
73 coins
74}
75
76pub fn setup_single_asset_coins(
80 owner: Address,
81 asset_id: AssetId,
82 num_coins: u64,
83 amount_per_coin: u64,
84) -> Vec<Coin> {
85 let mut rng = rand::thread_rng();
86
87 let coins: Vec<Coin> = (1..=num_coins)
88 .map(|_i| {
89 let mut r = Bytes32::zeroed();
90 r.try_fill(&mut rng)
91 .expect("failed to fill with random data");
92 let utxo_id = UtxoId::new(r, 0);
93
94 Coin {
95 owner,
96 utxo_id,
97 amount: amount_per_coin,
98 asset_id,
99 }
100 })
101 .collect();
102
103 coins
104}
105
106pub fn setup_single_message(
107 sender: Address,
108 recipient: Address,
109 amount: u64,
110 nonce: Nonce,
111 data: Vec<u8>,
112) -> Message {
113 Message {
114 sender,
115 recipient,
116 nonce,
117 amount,
118 data,
119 da_height: 0,
120 status: MessageStatus::Unspent,
121 }
122}
123
124pub async fn setup_test_provider(
125 coins: Vec<Coin>,
126 messages: Vec<Message>,
127 node_config: Option<NodeConfig>,
128 chain_config: Option<ChainConfig>,
129) -> Result<Provider> {
130 let node_config = node_config.unwrap_or_default();
131 let chain_config = chain_config.unwrap_or_else(testnet_chain_config);
132
133 let coin_configs = into_coin_configs(coins);
134 let message_configs = into_message_configs(messages);
135
136 let state_config = StateConfig {
137 coins: coin_configs,
138 messages: message_configs,
139 ..StateConfig::local_testnet()
140 };
141
142 let srv = FuelService::start(node_config, chain_config, state_config).await?;
143
144 let address = srv.bound_address();
145
146 tokio::spawn(async move {
147 let _own_the_handle = srv;
148 let () = futures::future::pending().await;
149 });
150
151 Provider::from(address).await
152}
153
154fn testnet_chain_config() -> ChainConfig {
156 let mut consensus_parameters = ConsensusParameters::default();
157 let tx_params = TxParameters::default().with_max_size(10_000_000);
158 let _ = consensus_parameters.set_block_transaction_size_limit(10_000_000);
161
162 let contract_params = ContractParameters::default().with_contract_max_size(1_000_000);
163 consensus_parameters.set_tx_params(tx_params);
164 consensus_parameters.set_contract_params(contract_params);
165
166 ChainConfig {
167 consensus_parameters,
168 ..ChainConfig::local_testnet()
169 }
170}
171
172pub fn generate_random_salt() -> [u8; 32] {
173 StdRng::from_entropy().r#gen()
174}
175
176#[cfg(test)]
177mod tests {
178 use std::net::{Ipv4Addr, SocketAddr};
179
180 use fuel_tx::{ConsensusParameters, ContractParameters, FeeParameters, TxParameters};
181
182 use super::*;
183
184 #[tokio::test]
185 async fn test_setup_single_asset_coins() -> Result<()> {
186 let mut rng = rand::thread_rng();
187 let address = rng.r#gen();
188
189 let mut asset_id = AssetId::zeroed();
190 asset_id
191 .try_fill(&mut rng)
192 .expect("failed to fill with random data");
193
194 let number_of_coins = 11;
195 let amount_per_coin = 10;
196 let coins = setup_single_asset_coins(address, asset_id, number_of_coins, amount_per_coin);
197
198 assert_eq!(coins.len() as u64, number_of_coins);
199 for coin in coins {
200 assert_eq!(coin.asset_id, asset_id);
201 assert_eq!(coin.amount, amount_per_coin);
202 assert_eq!(coin.owner, address);
203 }
204
205 Ok(())
206 }
207
208 #[tokio::test]
209 async fn test_setup_multiple_assets_coins() -> Result<()> {
210 let mut rng = rand::thread_rng();
211 let address = rng.r#gen();
212
213 let number_of_assets = 7;
214 let coins_per_asset = 10;
215 let amount_per_coin = 13;
216 let (coins, unique_asset_ids) = setup_multiple_assets_coins(
217 address,
218 number_of_assets,
219 coins_per_asset,
220 amount_per_coin,
221 );
222
223 assert_eq!(coins.len() as u64, number_of_assets * coins_per_asset);
224 assert_eq!(unique_asset_ids.len() as u64, number_of_assets);
225 assert!(
227 unique_asset_ids
228 .iter()
229 .any(|&asset_id| asset_id == AssetId::zeroed())
230 );
231 for asset_id in unique_asset_ids {
232 let coins_asset_id: Vec<Coin> = coins
233 .clone()
234 .into_iter()
235 .filter(|c| c.asset_id == asset_id)
236 .collect();
237 assert_eq!(coins_asset_id.len() as u64, coins_per_asset);
238 for coin in coins_asset_id {
239 assert_eq!(coin.owner, address);
240 assert_eq!(coin.amount, amount_per_coin);
241 }
242 }
243
244 Ok(())
245 }
246
247 #[tokio::test]
248 async fn test_setup_custom_assets_coins() -> Result<()> {
249 let mut rng = rand::thread_rng();
250 let address = rng.r#gen();
251
252 let asset_base = AssetConfig {
253 id: AssetId::zeroed(),
254 num_coins: 2,
255 coin_amount: 4,
256 };
257
258 let mut asset_id_1 = AssetId::zeroed();
259 asset_id_1
260 .try_fill(&mut rng)
261 .expect("failed to fill with random data");
262 let asset_1 = AssetConfig {
263 id: asset_id_1,
264 num_coins: 6,
265 coin_amount: 8,
266 };
267
268 let mut asset_id_2 = AssetId::zeroed();
269 asset_id_2
270 .try_fill(&mut rng)
271 .expect("failed to fill with random data");
272 let asset_2 = AssetConfig {
273 id: asset_id_2,
274 num_coins: 10,
275 coin_amount: 12,
276 };
277
278 let assets = vec![asset_base, asset_1, asset_2];
279 let coins = setup_custom_assets_coins(address, &assets);
280
281 for asset in assets {
282 let coins_asset_id: Vec<Coin> = coins
283 .clone()
284 .into_iter()
285 .filter(|c| c.asset_id == asset.id)
286 .collect();
287 assert_eq!(coins_asset_id.len() as u64, asset.num_coins);
288 for coin in coins_asset_id {
289 assert_eq!(coin.owner, address);
290 assert_eq!(coin.amount, asset.coin_amount);
291 }
292 }
293 Ok(())
294 }
295
296 #[tokio::test]
297 async fn test_setup_test_provider_custom_config() -> Result<()> {
298 let socket = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 4000);
299 let config = NodeConfig {
300 addr: socket,
301 ..NodeConfig::default()
302 };
303
304 let provider = setup_test_provider(vec![], vec![], Some(config.clone()), None).await?;
305 let node_info = provider
306 .node_info()
307 .await
308 .expect("Failed to retrieve node info!");
309
310 assert_eq!(provider.url(), format!("http://127.0.0.1:4000"));
311 assert_eq!(node_info.utxo_validation, config.utxo_validation);
312
313 Ok(())
314 }
315
316 #[tokio::test]
317 async fn test_setup_test_client_consensus_parameters_config() -> Result<()> {
318 let tx_params = TxParameters::default()
319 .with_max_gas_per_tx(2)
320 .with_max_inputs(58);
321 let fee_params = FeeParameters::default().with_gas_per_byte(2);
322 let contract_params = ContractParameters::default().with_max_storage_slots(83);
323
324 let mut consensus_parameters = ConsensusParameters::default();
325 consensus_parameters.set_tx_params(tx_params);
326 consensus_parameters.set_fee_params(fee_params);
327 consensus_parameters.set_contract_params(contract_params);
328
329 let chain_config = ChainConfig {
330 consensus_parameters: consensus_parameters.clone(),
331 ..ChainConfig::default()
332 };
333 let provider = setup_test_provider(vec![], vec![], None, Some(chain_config)).await?;
334
335 let retrieved_parameters = provider.consensus_parameters().await?;
336
337 assert_eq!(retrieved_parameters, consensus_parameters);
338
339 Ok(())
340 }
341
342 #[tokio::test]
343 async fn test_chain_config_and_consensus_parameters() -> Result<()> {
344 let max_inputs = 123;
345 let gas_per_byte = 456;
346
347 let mut consensus_parameters = ConsensusParameters::default();
348
349 let tx_params = TxParameters::default().with_max_inputs(max_inputs);
350 consensus_parameters.set_tx_params(tx_params);
351
352 let fee_params = FeeParameters::default().with_gas_per_byte(gas_per_byte);
353 consensus_parameters.set_fee_params(fee_params);
354
355 let chain_name = "fuel-0".to_string();
356 let chain_config = ChainConfig {
357 chain_name: chain_name.clone(),
358 consensus_parameters,
359 ..ChainConfig::local_testnet()
360 };
361
362 let provider = setup_test_provider(vec![], vec![], None, Some(chain_config)).await?;
363
364 let chain_info = provider.chain_info().await?;
365
366 assert_eq!(chain_info.name, chain_name);
367 assert_eq!(
368 chain_info.consensus_parameters.tx_params().max_inputs(),
369 max_inputs
370 );
371 assert_eq!(
372 chain_info.consensus_parameters.fee_params().gas_per_byte(),
373 gas_per_byte
374 );
375 Ok(())
376 }
377}