1#![allow(clippy::upper_case_acronyms)]
16mod grammar;
17
18use frame_system::Account;
19use fuzzed_runtime::{Balance, Balances, BalancesConfig, Runtime};
20use grammar::FuzzData;
21use pallet_balances::{Holds, TotalIssuance};
22use pallet_evm::{GasWeightMapping, Runner};
23use sp_core::H160;
24use sp_state_machine::BasicExternalities;
25
26fn main() {
27 ziggy::fuzz!(|data: FuzzData| {
28 let target = H160::from_low_u64_ne(2);
29 let gas_limit: u64 = 1_000_000;
30 new_test_ext().execute_with(|| {
31 let initial_total_issuance = TotalIssuance::<Runtime>::get();
32 let mut weight_limit =
33 pallet_evm::FixedGasWeightMapping::<Runtime>::gas_to_weight(gas_limit, true);
34 if data.check_proof_size {
35 *weight_limit.proof_size_mut() = weight_limit.proof_size() / 2;
36 }
37 let max_proof_size = weight_limit.proof_size();
38 let mut contract = vec![];
39 for op in &data.contract {
40 op.to_bytes(&mut contract);
41 }
42 pallet_evm::AccountCodes::<Runtime>::insert(target, contract);
43 let res = <Runtime as pallet_evm::Config>::Runner::call(
44 H160::default(),
45 target,
46 data.call_data,
47 data.value.into(),
48 gas_limit,
49 Some(1_000_000_000.into()),
50 None,
51 None,
52 Vec::new(),
53 Vec::new(),
54 true,
55 true,
56 Some(weight_limit),
57 Some(0u64),
58 &<Runtime as pallet_evm::Config>::config().clone(),
59 );
60 let proof_size = match res {
61 Ok(ref info) => info
62 .weight_info
63 .expect("weight info")
64 .proof_size_usage
65 .expect("proof size usage"),
66 Err(ref _info) => 0,
67 };
68 assert!(proof_size <= max_proof_size);
69 check_invariants(initial_total_issuance);
70 });
71 });
72}
73
74pub fn new_test_ext() -> BasicExternalities {
75 use sp_consensus_aura::sr25519::AuthorityId as AuraId;
76 use sp_runtime::{app_crypto::ByteArray, BuildStorage};
77 let accounts: Vec<fuzzed_runtime::AccountId> = (0..5).map(|i| [i; 32].into()).collect();
78 let t = fuzzed_runtime::RuntimeGenesisConfig {
79 system: Default::default(),
80 balances: BalancesConfig {
81 balances: accounts.iter().cloned().map(|k| (k, 1 << 80)).collect(),
83 ..Default::default()
84 },
85 base_fee: Default::default(),
86 evm_chain_id: Default::default(),
87 aura: fuzzed_runtime::AuraConfig {
88 authorities: vec![AuraId::from_slice(&[0; 32]).unwrap()],
89 },
90 sudo: fuzzed_runtime::SudoConfig { key: None },
91 transaction_payment: Default::default(),
92 grandpa: Default::default(),
93 manual_seal: Default::default(),
94 ethereum: Default::default(),
95 evm: Default::default(),
96 }
97 .build_storage()
98 .unwrap();
99 BasicExternalities::new(t)
100}
101
102fn check_invariants(initial_total_issuance: Balance) {
103 let mut counted_free: Balance = 0;
105 let mut counted_reserved: Balance = 0;
106 for (account, info) in Account::<Runtime>::iter() {
107 let consumers = info.consumers;
108 let providers = info.providers;
109 assert!(!(consumers > 0 && providers == 0), "Invalid c/p state");
110 counted_free += info.data.free;
111 counted_reserved += info.data.reserved;
112 let max_lock: Balance = Balances::locks(&account)
113 .iter()
114 .map(|l| l.amount)
115 .max()
116 .unwrap_or_default();
117 assert_eq!(
118 max_lock, info.data.frozen,
119 "Max lock should be equal to frozen balance"
120 );
121 let sum_holds: Balance = Holds::<Runtime>::get(account)
122 .iter()
123 .map(|l| l.amount)
124 .sum();
125 assert!(
126 sum_holds <= info.data.reserved,
127 "Sum of all holds ({sum_holds}) should be less than or equal to reserved balance {}",
128 info.data.reserved
129 );
130 }
131 let total_issuance = TotalIssuance::<Runtime>::get();
132 let counted_issuance = counted_free + counted_reserved;
133 assert_eq!(total_issuance, counted_issuance);
134 assert!(total_issuance <= initial_total_issuance);
135}