1use codec::Encode;
19use sc_block_builder::BlockBuilderBuilder;
20
21use crate::{construct_extrinsic, Client as TestClient};
22use cumulus_pallet_parachain_system::parachain_inherent::{
23 BasicParachainInherentData, InboundMessagesData,
24};
25use cumulus_primitives_core::{relay_chain::AccountId, PersistedValidationData};
26use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
27use cumulus_test_runtime::{
28 BalancesCall, GluttonCall, NodeBlock, SudoCall, UncheckedExtrinsic, WASM_BINARY,
29};
30use frame_system_rpc_runtime_api::AccountNonceApi;
31use polkadot_primitives::HeadData;
32use sc_client_api::UsageProvider;
33use sc_consensus::{
34 block_import::{BlockImportParams, ForkChoiceStrategy},
35 BlockImport, ImportResult, StateAction,
36};
37use sc_executor::DEFAULT_HEAP_ALLOC_STRATEGY;
38use sc_executor_common::runtime_blob::RuntimeBlob;
39use sp_api::ProvideRuntimeApi;
40use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed};
41use sp_consensus::BlockOrigin;
42use sp_core::{sr25519, Pair};
43use sp_keyring::Sr25519Keyring::Alice;
44use sp_runtime::{
45 transaction_validity::{InvalidTransaction, TransactionValidityError},
46 AccountId32, FixedU64, MultiAddress, OpaqueExtrinsic,
47};
48
49const NUM_ACCOUNTS: usize = 10000;
51
52pub fn create_benchmark_accounts() -> (Vec<sr25519::Pair>, Vec<sr25519::Pair>, Vec<AccountId32>) {
54 let accounts: Vec<sr25519::Pair> = (0..NUM_ACCOUNTS)
55 .map(|idx| {
56 Pair::from_string(&format!("{}/{}", Alice.to_seed(), idx), None)
57 .expect("Creates account pair")
58 })
59 .collect();
60 let account_ids = accounts
61 .iter()
62 .map(|account| AccountId::from(account.public()))
63 .collect::<Vec<AccountId>>();
64 let (src_accounts, dst_accounts) = accounts.split_at(NUM_ACCOUNTS / 2);
65 (src_accounts.to_vec(), dst_accounts.to_vec(), account_ids)
66}
67
68pub fn extrinsic_set_time(client: &TestClient) -> OpaqueExtrinsic {
70 let best_number = client.usage_info().chain.best_number;
71
72 let timestamp = best_number as u64 * cumulus_test_runtime::MinimumPeriod::get();
73 cumulus_test_runtime::UncheckedExtrinsic::new_bare(
74 cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set {
75 now: timestamp,
76 }),
77 )
78 .into()
79}
80
81pub fn extrinsic_set_validation_data(
83 parent_header: cumulus_test_runtime::Header,
84) -> OpaqueExtrinsic {
85 let parent_head = HeadData(parent_header.encode());
86 let sproof_builder = RelayStateSproofBuilder {
87 para_id: cumulus_test_runtime::PARACHAIN_ID.into(),
88 included_para_head: parent_head.clone().into(),
89 ..Default::default()
90 };
91
92 let (relay_parent_storage_root, relay_chain_state, relay_parent_descendants) =
93 sproof_builder.into_state_root_proof_and_descendants(1);
94 let data = BasicParachainInherentData {
95 validation_data: PersistedValidationData {
96 parent_head,
97 relay_parent_number: 10,
98 relay_parent_storage_root,
99 max_pov_size: 10000,
100 },
101 relay_chain_state,
102 relay_parent_descendants,
103 collator_peer_id: None,
104 };
105
106 let inbound_messages_data = InboundMessagesData {
107 downward_messages: Default::default(),
108 horizontal_messages: Default::default(),
109 };
110
111 cumulus_test_runtime::UncheckedExtrinsic::new_bare(
112 cumulus_test_runtime::RuntimeCall::ParachainSystem(
113 cumulus_pallet_parachain_system::Call::set_validation_data {
114 data,
115 inbound_messages_data,
116 },
117 ),
118 )
119 .into()
120}
121
122pub async fn import_block(client: &TestClient, block: &NodeBlock, import_existing: bool) {
124 let mut params = BlockImportParams::new(BlockOrigin::File, block.header.clone());
125 params.body = Some(block.extrinsics.clone());
126 params.state_action = StateAction::Execute;
127 params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
128 params.import_existing = import_existing;
129 let import_result = client.import_block(params).await;
130 assert!(
131 matches!(import_result, Ok(ImportResult::Imported(_))),
132 "Unexpected block import result: {:?}!",
133 import_result
134 );
135}
136
137pub fn create_benchmarking_transfer_extrinsics(
139 client: &TestClient,
140 src_accounts: &[sr25519::Pair],
141 dst_accounts: &[sr25519::Pair],
142) -> (usize, Vec<OpaqueExtrinsic>) {
143 let chain = client.usage_info().chain;
144 let mut block_builder = BlockBuilderBuilder::new(client)
146 .on_parent_block(chain.best_hash)
147 .with_parent_block_number(chain.best_number)
148 .build()
149 .expect("Creates block builder");
150 let mut max_transfer_count = 0;
151 let mut extrinsics = Vec::new();
152 let time_ext = extrinsic_set_time(client);
154 extrinsics.push(time_ext);
155
156 let parent_hash = client.usage_info().chain.best_hash;
158 let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap();
159 let set_validation_data_extrinsic = extrinsic_set_validation_data(parent_header);
160 extrinsics.push(set_validation_data_extrinsic);
161
162 for (src, dst) in src_accounts.iter().zip(dst_accounts.iter()) {
163 let extrinsic: UncheckedExtrinsic = construct_extrinsic(
164 client,
165 BalancesCall::transfer_keep_alive {
166 dest: MultiAddress::Id(AccountId::from(dst.public())),
167 value: 10000,
168 },
169 src.clone(),
170 Some(0),
171 );
172
173 match block_builder.push(extrinsic.clone().into()) {
174 Ok(_) => {},
175 Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid(
176 InvalidTransaction::ExhaustsResources,
177 )))) => break,
178 Err(error) => panic!("{}", error),
179 }
180
181 extrinsics.push(extrinsic.into());
182 max_transfer_count += 1;
183 }
184
185 if max_transfer_count >= src_accounts.len() {
186 panic!("Block could fit more transfers, increase NUM_ACCOUNTS to generate more accounts.");
187 }
188
189 (max_transfer_count, extrinsics)
190}
191
192pub fn get_wasm_module() -> Box<dyn sc_executor_common::wasm_runtime::WasmModule> {
194 let blob = RuntimeBlob::uncompress_if_needed(
195 WASM_BINARY.expect("You need to build the WASM binaries to run the benchmark!"),
196 )
197 .unwrap();
198
199 let config = sc_executor_wasmtime::Config {
200 allow_missing_func_imports: true,
201 cache_path: None,
202 semantics: sc_executor_wasmtime::Semantics {
203 heap_alloc_strategy: DEFAULT_HEAP_ALLOC_STRATEGY,
204 instantiation_strategy: sc_executor::WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
205 deterministic_stack_limit: None,
206 canonicalize_nans: false,
207 parallel_compilation: true,
208 wasm_multi_value: false,
209 wasm_bulk_memory: false,
210 wasm_reference_types: false,
211 wasm_simd: false,
212 },
213 };
214 Box::new(
215 sc_executor_wasmtime::create_runtime::<sp_io::SubstrateHostFunctions>(blob, config)
216 .expect("Unable to create wasm module."),
217 )
218}
219
220pub fn set_glutton_parameters(
222 client: &TestClient,
223 initialize: bool,
224 compute_ratio: &FixedU64,
225 storage_ratio: &FixedU64,
226) -> NodeBlock {
227 let parent_hash = client.usage_info().chain.best_hash;
228 let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap();
229
230 let mut last_nonce = client
231 .runtime_api()
232 .account_nonce(parent_hash, Alice.into())
233 .expect("Fetching account nonce works; qed");
234
235 let mut extrinsics = vec![];
236 if initialize {
237 extrinsics.push(construct_extrinsic(
239 client,
240 SudoCall::sudo {
241 call: Box::new(
242 GluttonCall::initialize_pallet { new_count: 5000, witness_count: None }.into(),
243 ),
244 },
245 Alice.into(),
246 Some(last_nonce),
247 ));
248 last_nonce += 1;
249 }
250
251 let set_compute = construct_extrinsic(
253 client,
254 SudoCall::sudo {
255 call: Box::new(GluttonCall::set_compute { compute: *compute_ratio }.into()),
256 },
257 Alice.into(),
258 Some(last_nonce),
259 );
260 last_nonce += 1;
261 extrinsics.push(set_compute);
262
263 let set_storage = construct_extrinsic(
265 client,
266 SudoCall::sudo {
267 call: Box::new(GluttonCall::set_storage { storage: *storage_ratio }.into()),
268 },
269 Alice.into(),
270 Some(last_nonce),
271 );
272 extrinsics.push(set_storage);
273 let chain = client.usage_info().chain;
274
275 let mut block_builder = BlockBuilderBuilder::new(client)
276 .on_parent_block(chain.best_hash)
277 .with_parent_block_number(chain.best_number)
278 .build()
279 .unwrap();
280 block_builder.push(extrinsic_set_time(client)).unwrap();
281 block_builder.push(extrinsic_set_validation_data(parent_header)).unwrap();
282 for extrinsic in extrinsics {
283 block_builder.push(extrinsic.into()).unwrap();
284 }
285
286 let built_block = block_builder.build().unwrap();
287 built_block.block
288}