Skip to content

Commit 0cc4dd3

Browse files
authored
refactor: separate pallet logic from entry file (#421)
* feat: add bench subcommand * feat: integrates frame-benchmarking-cli * refactor: PalletCmd run with spec * feat: set RUST_LOG=info for benchmarking display * feat: add CLI messages and tests * feat: add benchmark runtime wasm test * chore: fix comment * fix: operator cannot be applied to type * chore: display error and refactor test file * feat: auto detect wasm blob and build runtime * feat: build runtime wasm blob * refactor: build binary path method * fix: runtime path test * refactor: feature gating for benchmarking feature * chore: remove unused argument * fix: comment * chore: rename `bench` file * chore: rename `bench` file * feat: auto detect wasm blob and build runtime * feat: build runtime wasm blob * refactor: build binary path method * feat: list and select runtimes * chore: remove unused code * feat: auto detect wasm blob and build runtime * feat: build runtime wasm blob * refactor: build binary path method * chore: removed duplicate code * chore: remove spinner * chore: clippy warning * chore: clippy warning * refactor: parachain feature in bench command * chore: reorder imports * feat: add bench subcommand * feat: integrates frame-benchmarking-cli * refactor: PalletCmd run with spec * feat: set RUST_LOG=info for benchmarking display * feat: add CLI messages and tests * feat: add benchmark runtime wasm test * chore: fix comment * fix: operator cannot be applied to type * chore: display error and refactor test file * chore: rename `bench` file * chore: clippy warning * refactor: parachain feature in bench command * feat: add bench subcommand * feat: integrates frame-benchmarking-cli * refactor: PalletCmd run with spec * feat: add CLI messages and tests * feat: add benchmark runtime wasm test * chore: fix comment * fix: operator cannot be applied to type * chore: display error and refactor test file * chore: rename `bench` file * chore: clippy warning * refactor: parachain feature in bench command * chore: revert mod.rs * feat: select genesis builder * refactor: test helpers * chore: remove output display * chore: update parse genesis builder comment * fix: locate runtime and help command * chore: clippy warning * chore: display error message on binary check * fix: comment * feat: add genesis preset check (#422) * feat: add genesis preset check * feat: update_genesis_preset * refactor: constant name & add tests for preset * refactor: get_runtime_path * refactor: code order * refactor: test files * chore: clippy warning * refactor: list presets instead of manual input * feat: default to `none` if no presets found * refactor: build project test instead of runtime * chore: rebase * chore: reformat * chore: reformat * chore: rebase * chore: rebase
1 parent 0d9df52 commit 0cc4dd3

File tree

2 files changed

+381
-367
lines changed

2 files changed

+381
-367
lines changed
Lines changed: 4 additions & 367 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
11
// SPDX-License-Identifier: GPL-3.0
22

33
use crate::{
4-
cli::{
5-
self,
6-
traits::{Cli, Select},
7-
},
4+
cli::{self},
85
common::prompt::display_message,
96
};
107
use clap::{Args, Subcommand};
118
use frame_benchmarking_cli::PalletCmd;
12-
use pop_common::{manifest::from_path, Profile};
13-
use pop_parachains::{
14-
build_project, get_preset_names, get_runtime_path, parse_genesis_builder_policy,
15-
run_pallet_benchmarking, runtime_binary_path,
16-
};
17-
use std::{env::current_dir, fs, path::PathBuf};
9+
use pallet::BenchmarkPallet;
1810

19-
const GENESIS_BUILDER_NO_POLICY: &str = "none";
20-
const GENESIS_BUILDER_RUNTIME_POLICY: &str = "runtime";
11+
mod pallet;
2112

2213
/// Arguments for benchmarking a project.
2314
#[derive(Args)]
@@ -40,361 +31,7 @@ impl Command {
4031
pub(crate) fn execute(args: BenchmarkArgs) -> anyhow::Result<()> {
4132
let mut cli = cli::Cli;
4233
match args.command {
43-
Command::Pallet(mut cmd) => Command::bechmark_pallet(&mut cmd, &mut cli),
44-
}
45-
}
46-
47-
fn bechmark_pallet(cmd: &mut PalletCmd, cli: &mut impl Cli) -> anyhow::Result<()> {
48-
if cmd.list.is_some() || cmd.json_output {
49-
if let Err(e) = run_pallet_benchmarking(cmd) {
50-
return display_message(&e.to_string(), false, cli);
51-
}
52-
}
53-
cli.intro("Benchmarking your pallets")?;
54-
cli.warning(
55-
"NOTE: the `pop bench pallet` is not yet battle tested - double check the results.",
56-
)?;
57-
if let Some(ref spec) = cmd.shared_params.chain {
58-
return display_message(
59-
&format!(
60-
"Chain specs are not supported. Please remove `--chain={spec}` \
61-
and use `--runtime=<PATH>` instead"
62-
),
63-
false,
64-
cli,
65-
);
66-
}
67-
// No runtime path provided, auto-detect the runtime WASM binary. If not found, build
68-
// the runtime.
69-
if cmd.runtime.is_none() {
70-
match ensure_runtime_binary_exists(cli, &Profile::Release) {
71-
Ok(runtime_binary_path) => cmd.runtime = Some(runtime_binary_path),
72-
Err(e) => {
73-
return display_message(&e.to_string(), false, cli);
74-
},
75-
}
76-
}
77-
// Prompt user only if no genesis builder policy is set
78-
if cmd.genesis_builder.is_none() {
79-
if let Err(e) = guide_user_to_configure_genesis(cmd, cli) {
80-
return display_message(&e.to_string(), false, cli);
81-
}
82-
}
83-
84-
cli.warning("NOTE: this may take some time...")?;
85-
cli.info("Benchmarking and generating weight file...")?;
86-
if let Err(e) = run_pallet_benchmarking(cmd) {
87-
return display_message(&e.to_string(), false, cli);
88-
}
89-
display_message("Benchmark completed successfully!", true, cli)?;
90-
Ok(())
91-
}
92-
}
93-
94-
// Locate runtime WASM binary. If it doesn't exist, trigger build.
95-
fn ensure_runtime_binary_exists(
96-
cli: &mut impl cli::traits::Cli,
97-
mode: &Profile,
98-
) -> anyhow::Result<PathBuf> {
99-
let cwd = current_dir().unwrap_or(PathBuf::from("./"));
100-
let target_path = mode.target_directory(&cwd).join("wbuild");
101-
let mut project_path = get_runtime_path(&cwd)?;
102-
103-
// If there is no TOML file exist, list all directories in the "runtime" folder and prompt the
104-
// user to select a runtime.
105-
if !project_path.join("Cargo.toml").exists() {
106-
let runtime = guide_user_to_select_runtime(&project_path, cli)?;
107-
project_path = project_path.join(runtime);
108-
}
109-
110-
match runtime_binary_path(&target_path, &project_path) {
111-
Ok(binary_path) => Ok(binary_path),
112-
_ => {
113-
cli.info("Runtime binary was not found. The runtime will be built locally.")?;
114-
cli.warning("NOTE: this may take some time...")?;
115-
build_project(&project_path, None, mode, vec!["runtime-benchmarks"], None)?;
116-
runtime_binary_path(&target_path, &project_path).map_err(|e| e.into())
117-
},
118-
}
119-
}
120-
121-
fn guide_user_to_configure_genesis(
122-
cmd: &mut PalletCmd,
123-
cli: &mut impl cli::traits::Cli,
124-
) -> anyhow::Result<()> {
125-
let runtime_path = cmd.runtime.as_ref().expect("No runtime found.");
126-
let preset_names = get_preset_names(runtime_path)?;
127-
let policy = match preset_names.is_empty() {
128-
true => "none",
129-
false => guide_user_to_select_genesis_policy(cli)?,
130-
};
131-
132-
let parsed_policy = parse_genesis_builder_policy(policy)?;
133-
cmd.genesis_builder = parsed_policy.genesis_builder;
134-
if policy == GENESIS_BUILDER_RUNTIME_POLICY {
135-
cmd.genesis_builder_preset =
136-
guide_user_to_select_genesis_preset(cli, runtime_path, &cmd.genesis_builder_preset)?;
137-
}
138-
Ok(())
139-
}
140-
141-
fn guide_user_to_select_runtime(
142-
project_path: &PathBuf,
143-
cli: &mut impl cli::traits::Cli,
144-
) -> anyhow::Result<PathBuf> {
145-
let runtimes = fs::read_dir(project_path).unwrap();
146-
let mut prompt = cli.select("Select the runtime:");
147-
for runtime in runtimes {
148-
let path = runtime.unwrap().path();
149-
let manifest = from_path(Some(path.as_path()))?;
150-
let package = manifest.package();
151-
let name = package.clone().name;
152-
let description = package.description().unwrap_or_default().to_string();
153-
prompt = prompt.item(path, &name, &description);
154-
}
155-
Ok(prompt.interact()?)
156-
}
157-
158-
fn guide_user_to_select_genesis_policy(cli: &mut impl cli::traits::Cli) -> anyhow::Result<&str> {
159-
let mut prompt = cli.select("Select the genesis builder policy:").initial_value("none");
160-
for (policy, description) in [
161-
(GENESIS_BUILDER_NO_POLICY, "Do not provide any genesis state"),
162-
(
163-
GENESIS_BUILDER_RUNTIME_POLICY,
164-
"Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API",
165-
),
166-
] {
167-
prompt = prompt.item(policy, policy, description);
168-
}
169-
Ok(prompt.interact()?)
170-
}
171-
172-
fn guide_user_to_select_genesis_preset(
173-
cli: &mut impl cli::traits::Cli,
174-
runtime_path: &PathBuf,
175-
default_value: &str,
176-
) -> anyhow::Result<String> {
177-
let spinner = cliclack::spinner();
178-
spinner.start("Fetching available genesis builder presets of your runtime...");
179-
let mut prompt = cli
180-
.select("Select the genesis builder preset:")
181-
.initial_value(default_value.to_string());
182-
let preset_names = get_preset_names(runtime_path)?;
183-
if preset_names.is_empty() {
184-
return Err(anyhow::anyhow!("No preset found for the runtime"))
185-
}
186-
spinner.stop(format!("Found {} genesis builder presets", preset_names.len()));
187-
for preset in preset_names {
188-
prompt = prompt.item(preset.to_string(), preset, "");
189-
}
190-
Ok(prompt.interact()?)
191-
}
192-
193-
#[cfg(test)]
194-
mod tests {
195-
use super::*;
196-
use crate::cli::MockCli;
197-
use clap::Parser;
198-
use duct::cmd;
199-
use std::env;
200-
use tempfile::tempdir;
201-
202-
#[test]
203-
fn benchmark_pallet_works() -> anyhow::Result<()> {
204-
let mut cli =
205-
expect_select_genesis_policy(expect_pallet_benchmarking_intro(MockCli::new()), 0)
206-
.expect_warning("NOTE: this may take some time...")
207-
.expect_outro("Benchmark completed successfully!");
208-
209-
let mut cmd = PalletCmd::try_parse_from(&[
210-
"",
211-
"--runtime",
212-
get_mock_runtime_path(true).to_str().unwrap(),
213-
"--pallet",
214-
"pallet_timestamp",
215-
"--extrinsic",
216-
"",
217-
])?;
218-
Command::bechmark_pallet(&mut cmd, &mut cli)?;
219-
cli.verify()
220-
}
221-
222-
#[test]
223-
fn benchmark_pallet_with_chainspec_fails() -> anyhow::Result<()> {
224-
let spec = "path-to-chainspec";
225-
let mut cli =
226-
expect_pallet_benchmarking_intro(MockCli::new()).expect_outro_cancel(format!(
227-
"Chain specs are not supported. Please remove `--chain={spec}` \
228-
and use `--runtime=<PATH>` instead"
229-
));
230-
231-
let mut cmd = PalletCmd::try_parse_from(&[
232-
"",
233-
"--chain",
234-
spec,
235-
"--pallet",
236-
"pallet_timestamp",
237-
"--extrinsic",
238-
"",
239-
])?;
240-
241-
Command::bechmark_pallet(&mut cmd, &mut cli)?;
242-
cli.verify()
243-
}
244-
245-
#[test]
246-
fn benchmark_pallet_without_runtime_benchmarks_feature_fails() -> anyhow::Result<()> {
247-
let mut cli = expect_select_genesis_policy(expect_pallet_benchmarking_intro(MockCli::new()), 0)
248-
.expect_outro_cancel(
249-
"Failed to run benchmarking: Invalid input: Could not call runtime API to Did not find the benchmarking metadata. \
250-
This could mean that you either did not build the node correctly with the `--features runtime-benchmarks` flag, \
251-
or the chain spec that you are using was not created by a node that was compiled with the flag: \
252-
Other: Exported method Benchmark_benchmark_metadata is not found"
253-
);
254-
let mut cmd = PalletCmd::try_parse_from(&[
255-
"",
256-
"--runtime",
257-
get_mock_runtime_path(false).to_str().unwrap(),
258-
"--pallet",
259-
"pallet_timestamp",
260-
"--extrinsic",
261-
"",
262-
])?;
263-
Command::bechmark_pallet(&mut cmd, &mut cli)?;
264-
cli.verify()
265-
}
266-
267-
#[test]
268-
fn benchmark_pallet_fails_with_error() -> anyhow::Result<()> {
269-
let mut cli = expect_select_genesis_policy(expect_pallet_benchmarking_intro(MockCli::new()), 0)
270-
.expect_outro_cancel("Failed to run benchmarking: Invalid input: No benchmarks found which match your input.");
271-
let mut cmd = PalletCmd::try_parse_from(&[
272-
"",
273-
"--runtime",
274-
get_mock_runtime_path(true).to_str().unwrap(),
275-
"--pallet",
276-
"unknown-pallet-name",
277-
"--extrinsic",
278-
"",
279-
])?;
280-
Command::bechmark_pallet(&mut cmd, &mut cli)?;
281-
cli.verify()
282-
}
283-
284-
#[test]
285-
fn guide_user_to_select_runtime_works() -> anyhow::Result<()> {
286-
let temp_dir = tempdir()?;
287-
let runtime_path = temp_dir.path().join("runtime");
288-
let runtimes = ["runtime-1", "runtime-2", "runtime-3"];
289-
let mut cli = MockCli::new().expect_select(
290-
"Select the runtime:",
291-
Some(true),
292-
true,
293-
Some(runtimes.map(|runtime| (runtime.to_string(), "".to_string())).to_vec()),
294-
0,
295-
);
296-
fs::create_dir(&runtime_path)?;
297-
for runtime in runtimes {
298-
cmd("cargo", ["new", runtime, "--bin"]).dir(&runtime_path).run()?;
34+
Command::Pallet(mut cmd) => BenchmarkPallet.execute(&mut cmd, &mut cli),
29935
}
300-
guide_user_to_select_runtime(&runtime_path, &mut cli)?;
301-
cli.verify()
302-
}
303-
304-
#[test]
305-
fn guide_user_to_configure_genesis_works() -> anyhow::Result<()> {
306-
let runtime_path = get_mock_runtime_path(false);
307-
let mut cli = expect_select_genesis_preset(
308-
expect_select_genesis_policy(MockCli::new(), 1),
309-
&runtime_path,
310-
0,
311-
);
312-
let mut cmd = PalletCmd::try_parse_from(&[
313-
"",
314-
"--runtime",
315-
runtime_path.to_str().unwrap(),
316-
"--pallet",
317-
"",
318-
"--extrinsic",
319-
"",
320-
])?;
321-
guide_user_to_configure_genesis(&mut cmd, &mut cli)?;
322-
assert_eq!(cmd.genesis_builder, parse_genesis_builder_policy("runtime")?.genesis_builder);
323-
assert_eq!(
324-
cmd.genesis_builder_preset,
325-
get_preset_names(&runtime_path)?.first().cloned().unwrap_or_default()
326-
);
327-
cli.verify()
328-
}
329-
330-
#[test]
331-
fn guide_user_to_select_genesis_policy_works() -> anyhow::Result<()> {
332-
// Select genesis builder policy `none`.
333-
let mut cli = expect_select_genesis_policy(MockCli::new(), 0);
334-
guide_user_to_select_genesis_policy(&mut cli)?;
335-
cli.verify()?;
336-
337-
// Select genesis builder policy `runtime`.
338-
let runtime_path = get_mock_runtime_path(false);
339-
cli = expect_select_genesis_preset(
340-
expect_select_genesis_policy(MockCli::new(), 1),
341-
&runtime_path,
342-
0,
343-
);
344-
guide_user_to_select_genesis_policy(&mut cli)?;
345-
guide_user_to_select_genesis_preset(&mut cli, &runtime_path, "development")?;
346-
cli.verify()
347-
}
348-
349-
#[test]
350-
fn guide_user_to_select_genesis_preset_works() -> anyhow::Result<()> {
351-
let runtime_path = get_mock_runtime_path(false);
352-
let mut cli = expect_select_genesis_preset(MockCli::new(), &runtime_path, 0);
353-
guide_user_to_select_genesis_preset(&mut cli, &runtime_path, "development")?;
354-
cli.verify()
355-
}
356-
357-
fn expect_pallet_benchmarking_intro(cli: MockCli) -> MockCli {
358-
cli.expect_intro("Benchmarking your pallets").expect_warning(
359-
"NOTE: the `pop bench pallet` is not yet battle tested - double check the results.",
360-
)
361-
}
362-
363-
fn expect_select_genesis_policy(cli: MockCli, item: usize) -> MockCli {
364-
let policies = vec![
365-
(GENESIS_BUILDER_NO_POLICY.to_string(), "Do not provide any genesis state".to_string()),
366-
(GENESIS_BUILDER_RUNTIME_POLICY.to_string(), "Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API".to_string())
367-
];
368-
cli.expect_select(
369-
"Select the genesis builder policy:",
370-
Some(true),
371-
true,
372-
Some(policies),
373-
item,
374-
)
375-
}
376-
377-
fn expect_select_genesis_preset(cli: MockCli, runtime_path: &PathBuf, item: usize) -> MockCli {
378-
let preset_names = get_preset_names(runtime_path)
379-
.unwrap()
380-
.into_iter()
381-
.map(|preset| (preset, String::default()))
382-
.collect();
383-
cli.expect_select(
384-
"Select the genesis builder preset:",
385-
Some(true),
386-
true,
387-
Some(preset_names),
388-
item,
389-
)
390-
}
391-
392-
// Construct the path to the mock runtime WASM file.
393-
fn get_mock_runtime_path(with_benchmark_features: bool) -> std::path::PathBuf {
394-
let path = format!(
395-
"../../tests/runtimes/{}.wasm",
396-
if with_benchmark_features { "base_parachain_benchmark" } else { "base_parachain" }
397-
);
398-
env::current_dir().unwrap().join(path).canonicalize().unwrap()
39936
}
40037
}

0 commit comments

Comments
 (0)