fuel_chain_config/
config.rs

1mod chain;
2mod coin;
3mod contract;
4mod message;
5mod state;
6
7pub use chain::*;
8pub use coin::*;
9pub use contract::*;
10pub use message::*;
11pub use state::*;
12
13#[cfg(test)]
14mod tests {
15    use fuel_core_interfaces::{
16        common::{
17            fuel_asm::Opcode,
18            fuel_vm::prelude::Contract,
19            prelude::{
20                AssetId,
21                Bytes32,
22            },
23        },
24        model::DaBlockHeight,
25    };
26    use rand::{
27        prelude::StdRng,
28        Rng,
29        RngCore,
30        SeedableRng,
31    };
32    use std::{
33        env::temp_dir,
34        fs::write,
35        path::PathBuf,
36    };
37
38    use super::{
39        chain::ChainConfig,
40        coin::CoinConfig,
41        contract::ContractConfig,
42        message::MessageConfig,
43        state::StateConfig,
44    };
45
46    #[test]
47    fn from_str_loads_from_file() {
48        // setup chain config in a temp file
49        let tmp_file = tmp_path();
50        let disk_config = ChainConfig::local_testnet();
51        let json = serde_json::to_string_pretty(&disk_config).unwrap();
52        write(tmp_file.clone(), json).unwrap();
53
54        // test loading config from file path string
55        let load_config: ChainConfig =
56            tmp_file.to_string_lossy().into_owned().parse().unwrap();
57        assert_eq!(disk_config, load_config);
58    }
59
60    #[test]
61    fn snapshot_local_testnet_config() {
62        let config = ChainConfig::local_testnet();
63        let json = serde_json::to_string_pretty(&config).unwrap();
64        insta::assert_snapshot!(json);
65    }
66
67    #[test]
68    fn can_roundtrip_serialize_local_testnet_config() {
69        let config = ChainConfig::local_testnet();
70        let json = serde_json::to_string(&config).unwrap();
71        let deserialized_config: ChainConfig =
72            serde_json::from_str(json.as_str()).unwrap();
73        assert_eq!(config, deserialized_config);
74    }
75
76    #[test]
77    fn snapshot_configurable_block_height() {
78        let mut rng = StdRng::seed_from_u64(2);
79        let config = ChainConfig {
80            initial_state: Some(StateConfig {
81                height: Some(rng.next_u32().into()),
82                ..Default::default()
83            }),
84            ..ChainConfig::local_testnet()
85        };
86        let json = serde_json::to_string_pretty(&config).unwrap();
87        insta::assert_snapshot!(json);
88    }
89
90    #[test]
91    fn can_roundtrip_serialize_block_height_config() {
92        let mut rng = StdRng::seed_from_u64(2);
93        let config = ChainConfig {
94            initial_state: Some(StateConfig {
95                height: Some(rng.next_u32().into()),
96                ..Default::default()
97            }),
98            ..ChainConfig::local_testnet()
99        };
100        let json = serde_json::to_string(&config).unwrap();
101        let deserialized_config: ChainConfig =
102            serde_json::from_str(json.as_str()).unwrap();
103        assert_eq!(config, deserialized_config);
104    }
105
106    #[test]
107    fn snapshot_simple_contract() {
108        let config = test_config_contract(false, false);
109        let json = serde_json::to_string_pretty(&config).unwrap();
110        insta::assert_snapshot!(json);
111    }
112
113    #[test]
114    fn can_roundtrip_simple_contract() {
115        let config = test_config_contract(false, false);
116        let json = serde_json::to_string(&config).unwrap();
117        let deserialized_config: ChainConfig =
118            serde_json::from_str(json.as_str()).unwrap();
119        assert_eq!(config, deserialized_config);
120    }
121
122    #[test]
123    fn snapshot_contract_with_state() {
124        let config = test_config_contract(true, false);
125        let json = serde_json::to_string_pretty(&config).unwrap();
126        insta::assert_snapshot!(json);
127    }
128
129    #[test]
130    fn can_roundtrip_contract_with_state() {
131        let config = test_config_contract(true, false);
132        let json = serde_json::to_string(&config).unwrap();
133        let deserialized_config: ChainConfig =
134            serde_json::from_str(json.as_str()).unwrap();
135        assert_eq!(config, deserialized_config);
136    }
137
138    #[test]
139    fn snapshot_contract_with_balances() {
140        let config = test_config_contract(false, true);
141        let json = serde_json::to_string_pretty(&config).unwrap();
142        insta::assert_snapshot!(json);
143    }
144
145    #[test]
146    fn can_roundtrip_contract_with_balances() {
147        let config = test_config_contract(false, true);
148        let json = serde_json::to_string(&config).unwrap();
149        let deserialized_config: ChainConfig =
150            serde_json::from_str(json.as_str()).unwrap();
151        assert_eq!(config, deserialized_config);
152    }
153
154    #[test]
155    fn snapshot_simple_coin_state() {
156        let config = test_config_coin_state();
157        let json = serde_json::to_string_pretty(&config).unwrap();
158        insta::assert_snapshot!(json);
159    }
160
161    #[test]
162    fn can_roundtrip_simple_coin_state() {
163        let config = test_config_coin_state();
164        let json = serde_json::to_string(&config).unwrap();
165        let deserialized_config: ChainConfig =
166            serde_json::from_str(json.as_str()).unwrap();
167        assert_eq!(config, deserialized_config);
168    }
169
170    #[test]
171    fn snapshot_simple_message_state() {
172        let config = test_message_config();
173        let json = serde_json::to_string_pretty(&config).unwrap();
174        insta::assert_snapshot!(json);
175    }
176
177    #[test]
178    fn can_roundtrip_simple_message_state() {
179        let config = test_message_config();
180        let json = serde_json::to_string(&config).unwrap();
181        let deserialized_config: ChainConfig =
182            serde_json::from_str(json.as_str()).unwrap();
183        assert_eq!(config, deserialized_config);
184    }
185
186    fn test_config_contract(state: bool, balances: bool) -> ChainConfig {
187        let mut rng = StdRng::seed_from_u64(1);
188        let state = if state {
189            let test_key: Bytes32 = rng.gen();
190            let test_value: Bytes32 = rng.gen();
191            Some(vec![(test_key, test_value)])
192        } else {
193            None
194        };
195        let balances = if balances {
196            let test_asset_id: AssetId = rng.gen();
197            let test_balance: u64 = rng.next_u64();
198            Some(vec![(test_asset_id, test_balance)])
199        } else {
200            None
201        };
202
203        let contract = Contract::from(Opcode::RET(0x10).to_bytes().to_vec());
204
205        ChainConfig {
206            initial_state: Some(StateConfig {
207                contracts: Some(vec![ContractConfig {
208                    code: contract.into(),
209                    salt: Default::default(),
210                    state,
211                    balances,
212                }]),
213                ..Default::default()
214            }),
215            ..ChainConfig::local_testnet()
216        }
217    }
218
219    fn test_config_coin_state() -> ChainConfig {
220        let mut rng = StdRng::seed_from_u64(1);
221        let tx_id: Option<Bytes32> = Some(rng.gen());
222        let output_index: Option<u64> = Some(rng.gen());
223        let block_created = Some(rng.next_u32().into());
224        let maturity = Some(rng.next_u32().into());
225        let owner = rng.gen();
226        let amount = rng.gen();
227        let asset_id = rng.gen();
228
229        ChainConfig {
230            initial_state: Some(StateConfig {
231                coins: Some(vec![CoinConfig {
232                    tx_id,
233                    output_index,
234                    block_created,
235                    maturity,
236                    owner,
237                    amount,
238                    asset_id,
239                }]),
240                ..Default::default()
241            }),
242            ..ChainConfig::local_testnet()
243        }
244    }
245
246    fn test_message_config() -> ChainConfig {
247        let mut rng = StdRng::seed_from_u64(1);
248
249        ChainConfig {
250            initial_state: Some(StateConfig {
251                messages: Some(vec![MessageConfig {
252                    sender: rng.gen(),
253                    recipient: rng.gen(),
254                    nonce: rng.gen(),
255                    amount: rng.gen(),
256                    data: vec![rng.gen()],
257                    da_height: DaBlockHeight(rng.gen()),
258                }]),
259                ..Default::default()
260            }),
261            ..ChainConfig::local_testnet()
262        }
263    }
264
265    fn tmp_path() -> PathBuf {
266        let mut path = temp_dir();
267        path.push(rand::random::<u16>().to_string());
268        path
269    }
270}