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) = sproof_builder.into_state_root_and_proof();
93 let data = BasicParachainInherentData {
94 validation_data: PersistedValidationData {
95 parent_head,
96 relay_parent_number: 10,
97 relay_parent_storage_root,
98 max_pov_size: 10000,
99 },
100 relay_chain_state,
101 relay_parent_descendants: Default::default(),
102 collator_peer_id: None,
103 };
104
105 let inbound_messages_data = InboundMessagesData {
106 downward_messages: Default::default(),
107 horizontal_messages: Default::default(),
108 };
109
110 cumulus_test_runtime::UncheckedExtrinsic::new_bare(
111 cumulus_test_runtime::RuntimeCall::ParachainSystem(
112 cumulus_pallet_parachain_system::Call::set_validation_data {
113 data,
114 inbound_messages_data,
115 },
116 ),
117 )
118 .into()
119}
120
121pub async fn import_block(client: &TestClient, block: &NodeBlock, import_existing: bool) {
123 let mut params = BlockImportParams::new(BlockOrigin::File, block.header.clone());
124 params.body = Some(block.extrinsics.clone());
125 params.state_action = StateAction::Execute;
126 params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
127 params.import_existing = import_existing;
128 let import_result = client.import_block(params).await;
129 assert!(
130 matches!(import_result, Ok(ImportResult::Imported(_))),
131 "Unexpected block import result: {:?}!",
132 import_result
133 );
134}
135
136pub fn create_benchmarking_transfer_extrinsics(
138 client: &TestClient,
139 src_accounts: &[sr25519::Pair],
140 dst_accounts: &[sr25519::Pair],
141) -> (usize, Vec<OpaqueExtrinsic>) {
142 let chain = client.usage_info().chain;
143 let mut block_builder = BlockBuilderBuilder::new(client)
145 .on_parent_block(chain.best_hash)
146 .with_parent_block_number(chain.best_number)
147 .build()
148 .expect("Creates block builder");
149 let mut max_transfer_count = 0;
150 let mut extrinsics = Vec::new();
151 let time_ext = extrinsic_set_time(client);
153 extrinsics.push(time_ext);
154
155 let parent_hash = client.usage_info().chain.best_hash;
157 let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap();
158 let set_validation_data_extrinsic = extrinsic_set_validation_data(parent_header);
159 extrinsics.push(set_validation_data_extrinsic);
160
161 for (src, dst) in src_accounts.iter().zip(dst_accounts.iter()) {
162 let extrinsic: UncheckedExtrinsic = construct_extrinsic(
163 client,
164 BalancesCall::transfer_keep_alive {
165 dest: MultiAddress::Id(AccountId::from(dst.public())),
166 value: 10000,
167 },
168 src.clone(),
169 Some(0),
170 );
171
172 match block_builder.push(extrinsic.clone().into()) {
173 Ok(_) => {},
174 Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid(
175 InvalidTransaction::ExhaustsResources,
176 )))) => break,
177 Err(error) => panic!("{}", error),
178 }
179
180 extrinsics.push(extrinsic.into());
181 max_transfer_count += 1;
182 }
183
184 if max_transfer_count >= src_accounts.len() {
185 panic!("Block could fit more transfers, increase NUM_ACCOUNTS to generate more accounts.");
186 }
187
188 (max_transfer_count, extrinsics)
189}
190
191pub fn get_wasm_module() -> Box<dyn sc_executor_common::wasm_runtime::WasmModule> {
193 let blob = RuntimeBlob::uncompress_if_needed(
194 WASM_BINARY.expect("You need to build the WASM binaries to run the benchmark!"),
195 )
196 .unwrap();
197
198 let config = sc_executor_wasmtime::Config {
199 allow_missing_func_imports: true,
200 cache_path: None,
201 semantics: sc_executor_wasmtime::Semantics {
202 heap_alloc_strategy: DEFAULT_HEAP_ALLOC_STRATEGY,
203 instantiation_strategy: sc_executor::WasmtimeInstantiationStrategy::PoolingCopyOnWrite,
204 deterministic_stack_limit: None,
205 canonicalize_nans: false,
206 parallel_compilation: true,
207 wasm_multi_value: false,
208 wasm_bulk_memory: false,
209 wasm_reference_types: false,
210 wasm_simd: false,
211 },
212 };
213 Box::new(
214 sc_executor_wasmtime::create_runtime::<sp_io::SubstrateHostFunctions>(blob, config)
215 .expect("Unable to create wasm module."),
216 )
217}
218
219pub fn set_glutton_parameters(
221 client: &TestClient,
222 initialize: bool,
223 compute_ratio: &FixedU64,
224 storage_ratio: &FixedU64,
225) -> NodeBlock {
226 let parent_hash = client.usage_info().chain.best_hash;
227 let parent_header = client.header(parent_hash).expect("Just fetched this hash.").unwrap();
228
229 let mut last_nonce = client
230 .runtime_api()
231 .account_nonce(parent_hash, Alice.into())
232 .expect("Fetching account nonce works; qed");
233
234 let mut extrinsics = vec![];
235 if initialize {
236 extrinsics.push(construct_extrinsic(
238 client,
239 SudoCall::sudo {
240 call: Box::new(
241 GluttonCall::initialize_pallet { new_count: 5000, witness_count: None }.into(),
242 ),
243 },
244 Alice.into(),
245 Some(last_nonce),
246 ));
247 last_nonce += 1;
248 }
249
250 let set_compute = construct_extrinsic(
252 client,
253 SudoCall::sudo {
254 call: Box::new(GluttonCall::set_compute { compute: *compute_ratio }.into()),
255 },
256 Alice.into(),
257 Some(last_nonce),
258 );
259 last_nonce += 1;
260 extrinsics.push(set_compute);
261
262 let set_storage = construct_extrinsic(
264 client,
265 SudoCall::sudo {
266 call: Box::new(GluttonCall::set_storage { storage: *storage_ratio }.into()),
267 },
268 Alice.into(),
269 Some(last_nonce),
270 );
271 extrinsics.push(set_storage);
272 let chain = client.usage_info().chain;
273
274 let mut block_builder = BlockBuilderBuilder::new(client)
275 .on_parent_block(chain.best_hash)
276 .with_parent_block_number(chain.best_number)
277 .build()
278 .unwrap();
279 block_builder.push(extrinsic_set_time(client)).unwrap();
280 block_builder.push(extrinsic_set_validation_data(parent_header)).unwrap();
281 for extrinsic in extrinsics {
282 block_builder.push(extrinsic.into()).unwrap();
283 }
284
285 let built_block = block_builder.build().unwrap();
286 built_block.block
287}