Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: logic for parachain registration #410

Open
wants to merge 22 commits into
base: feat/deploy-parachain
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
77309e2
feat: deploy a parachain commands
AlexD10S Feb 10, 2025
f9dffc6
feat: build specs in pop up
AlexD10S Feb 10, 2025
8016272
feat: logic to interact with a chain
AlexD10S Feb 11, 2025
11869aa
feat: register parachain
AlexD10S Feb 11, 2025
d30c135
refactor: clean code and improve docs
AlexD10S Feb 11, 2025
9bd7229
test: unit tests for pop up methods
AlexD10S Feb 11, 2025
5952580
refactor: small fixes with visibility and removing logs
AlexD10S Feb 12, 2025
d5bd298
feat: return events in submit_signed_extrinsic
AlexD10S Feb 13, 2025
6abeba8
feat: get para_id from event
AlexD10S Feb 14, 2025
d360dba
test: fix detects_parachain_correctly
AlexD10S Feb 17, 2025
7f9b926
refactor: improve docs and code
AlexD10S Feb 17, 2025
ece5507
test: fix change_working_directory_works
AlexD10S Feb 17, 2025
e413871
fix: clippy warnings
AlexD10S Feb 18, 2025
7d87f17
refactor: move submit_extrinsic_with_wallet in a common file
AlexD10S Feb 20, 2025
ae3d9a4
refactor: remove unnecesary code
AlexD10S Feb 20, 2025
54a676e
refactor: UpChainCommand structure
AlexD10S Feb 20, 2025
db6e30d
test: adjust tests to refactored struct
AlexD10S Feb 20, 2025
50983c1
refactor: renaming prepare_register_parachain_call_data and prepare_r…
AlexD10S Feb 20, 2025
cfc566e
refactor: move events module
AlexD10S Feb 20, 2025
93053df
fix: submit_extrinsic_with_wallet under parachain feature
AlexD10S Feb 20, 2025
849dff0
refactor: remove unnecesary code
AlexD10S Feb 20, 2025
74cf390
test: increase coverage with reserve_parachain_id_fails_wrong_chain a…
AlexD10S Feb 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ subxt = "0.38.0"
ink_env = "5.0.0"
sp-core = "32.0.0"
sp-weights = "31.0.0"
scale = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] }
scale-info = { version = "2.11.4", default-features = false, features = ["derive"] }
scale-value = { version = "0.17.0", default-features = false, features = ["from-string", "parser-ss58"] }
contract-build = "5.0.2"
Expand Down
88 changes: 61 additions & 27 deletions crates/pop-cli/src/commands/build/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
style::style,
};
use clap::{Args, ValueEnum};
use cliclack::spinner;
use cliclack::{spinner, ProgressBar};
use pop_common::Profile;
use pop_parachains::{
binary_path, build_parachain, export_wasm_file, generate_genesis_state_file,
Expand Down Expand Up @@ -193,7 +193,7 @@ impl BuildSpecCommand {
///
/// # Arguments
/// * `cli` - The cli.
async fn configure_build_spec(
pub(crate) async fn configure_build_spec(
self,
cli: &mut impl cli::traits::Cli,
) -> anyhow::Result<BuildSpec> {
Expand Down Expand Up @@ -439,7 +439,7 @@ impl BuildSpecCommand {

// Represents the configuration for building a chain specification.
#[derive(Debug)]
struct BuildSpec {
pub(crate) struct BuildSpec {
output_file: PathBuf,
profile: Profile,
id: u32,
Expand All @@ -461,39 +461,18 @@ impl BuildSpec {
fn build(self, cli: &mut impl cli::traits::Cli) -> anyhow::Result<&'static str> {
cli.intro("Building your chain spec")?;
let mut generated_files = vec![];
let BuildSpec {
ref output_file,
ref profile,
id,
default_bootnode,
ref chain,
genesis_state,
genesis_code,
..
} = self;
let BuildSpec { ref output_file, ref profile, id, genesis_code, genesis_state, .. } = self;
// Ensure binary is built.
let binary_path = ensure_binary_exists(cli, profile)?;
let spinner = spinner();
spinner.start("Generating chain specification...");

// Generate chain spec.
generate_plain_chain_spec(&binary_path, output_file, default_bootnode, chain)?;
Copy link
Collaborator Author

@AlexD10S AlexD10S Feb 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored the logic for generating the chain spec and raw chain spec into the generate_chain_spec function.

// Customize spec based on input.
self.customize()?;
let raw_chain_spec = self.generate_chain_spec(&binary_path, &spinner)?;

generated_files.push(format!(
"Plain text chain specification file generated at: {}",
&output_file.display()
));

// Generate raw spec.
spinner.set_message("Generating raw chain specification...");
let spec_name = &output_file
.file_name()
.and_then(|s| s.to_str())
.unwrap_or(DEFAULT_SPEC_NAME)
.trim_end_matches(".json");
let raw_spec_name = format!("{spec_name}-raw.json");
let raw_chain_spec = generate_raw_chain_spec(&binary_path, output_file, &raw_spec_name)?;
generated_files.push(format!(
"Raw chain specification file generated at: {}",
raw_chain_spec.display()
Expand Down Expand Up @@ -529,6 +508,61 @@ impl BuildSpec {
Ok("spec")
}

/// Generates plain and raw chain specification files, and returns the path to the latter.
fn generate_chain_spec(
&self,
binary_path: &Path,
spinner: &ProgressBar,
) -> anyhow::Result<PathBuf> {
let BuildSpec { output_file, chain, .. } = self;
spinner.start("Generating chain specification...");

// Generate plain chain spec.
generate_plain_chain_spec(binary_path, output_file, self.default_bootnode, chain)?;
// Customize spec based on input.
self.customize()?;

// Generate raw spec.
spinner.set_message("Generating raw chain specification...");
let spec_name = &output_file
.file_name()
.and_then(|s| s.to_str())
.unwrap_or(DEFAULT_SPEC_NAME)
.trim_end_matches(".json");
let raw_spec_name = format!("{spec_name}-raw.json");
generate_raw_chain_spec(binary_path, output_file, &raw_spec_name)
.map_err(anyhow::Error::from)
}

/// Generates chain specification files and returns the file paths for the generated genesis
/// code and genesis state files.
///
/// # Arguments
/// * `cli` - The cli.
pub(crate) fn generate_genesis_artifacts(
self,
cli: &mut impl cli::traits::Cli,
) -> anyhow::Result<(PathBuf, PathBuf)> {
// Ensure binary is built once.
let binary_path = ensure_binary_exists(cli, &self.profile)?;
let spinner = spinner();
spinner.start("Generating files...");

let raw_chain_spec = self.generate_chain_spec(&binary_path, &spinner)?;

spinner.set_message("Generating genesis code...");
let wasm_file_name = format!("para-{}.wasm", self.id);
let genesis_code = export_wasm_file(&binary_path, &raw_chain_spec, &wasm_file_name)?;

spinner.set_message("Generating genesis state...");
let genesis_file_name = format!("para-{}-genesis-state", self.id);
let genesis_state =
generate_genesis_state_file(&binary_path, &raw_chain_spec, &genesis_file_name)?;

spinner.stop("Genesis artifacts generated successfully.");
Ok((genesis_state, genesis_code))
}

// Customize a chain specification.
fn customize(&self) -> anyhow::Result<()> {
let mut chain_spec = ChainSpec::from(&self.output_file)?;
Expand Down
50 changes: 13 additions & 37 deletions crates/pop-cli/src/commands/call/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ use std::path::Path;

use crate::{
cli::{self, traits::*},
common::wallet::{prompt_to_use_wallet, request_signature},
common::wallet::{prompt_to_use_wallet, submit_extrinsic_with_wallet},
};
use anyhow::{anyhow, Result};
use clap::Args;
use pop_parachains::{
construct_extrinsic, construct_sudo_extrinsic, decode_call_data, encode_call_data,
find_dispatchable_by_name, find_pallet_by_name, parse_chain_metadata, set_up_client,
sign_and_submit_extrinsic, submit_signed_extrinsic, supported_actions, Action, CallData,
DynamicPayload, Function, OnlineClient, Pallet, Param, Payload, SubstrateConfig,
sign_and_submit_extrinsic, supported_actions, Action, CallData, DynamicPayload, Function,
OnlineClient, Pallet, Param, Payload, SubstrateConfig,
};
use url::Url;

Expand Down Expand Up @@ -109,7 +109,9 @@ impl CallChainCommand {
// Sign and submit the extrinsic.
let result = if self.use_wallet {
let call_data = xt.encode_call_data(&chain.client.metadata())?;
submit_extrinsic_with_wallet(&chain.client, &chain.url, call_data, &mut cli).await
submit_extrinsic_with_wallet(&chain.client, &chain.url, call_data, &mut cli)
.await
.map(|_| ()) // Mapping to `()` since we don't need events returned
} else {
call.submit_extrinsic(&chain.client, &chain.url, xt, &mut cli).await
};
Expand Down Expand Up @@ -358,19 +360,19 @@ impl CallChainCommand {
}

// Represents a chain, including its URL, client connection, and available pallets.
struct Chain {
pub(crate) struct Chain {
// Websocket endpoint of the node.
url: Url,
pub(crate) url: Url,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trivial but line 363 already set this struct to pub(crate), we can simply set this field to pub.

// The client used to interact with the chain.
client: OnlineClient<SubstrateConfig>,
pub(crate) client: OnlineClient<SubstrateConfig>,
// A list of pallets available on the chain.
pallets: Vec<Pallet>,
pub(crate) pallets: Vec<Pallet>,
}

/// Represents a configured dispatchable function call, including the pallet, function, arguments,
/// and signing options.
#[derive(Clone)]
struct Call {
#[derive(Clone, Default)]
pub struct Call {
/// The dispatchable function to execute.
function: Function,
/// The dispatchable function arguments, encoded as strings.
Expand All @@ -391,7 +393,7 @@ struct Call {

impl Call {
// Prepares the extrinsic.
fn prepare_extrinsic(
pub fn prepare_extrinsic(
&self,
client: &OnlineClient<SubstrateConfig>,
cli: &mut impl Cli,
Expand Down Expand Up @@ -473,32 +475,6 @@ impl Call {
}
}

// Sign and submit an extrinsic using wallet integration.
async fn submit_extrinsic_with_wallet(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For context: Moved into common/wallet

client: &OnlineClient<SubstrateConfig>,
url: &Url,
call_data: Vec<u8>,
cli: &mut impl Cli,
) -> Result<()> {
let maybe_payload = request_signature(call_data, url.to_string()).await?;
if let Some(payload) = maybe_payload {
cli.success("Signed payload received.")?;
let spinner = cliclack::spinner();
spinner.start(
"Submitting the extrinsic and then waiting for finalization, please be patient...",
);

let result = submit_signed_extrinsic(client.clone(), payload)
.await
.map_err(|err| anyhow!("{}", format!("{err:?}")))?;

spinner.stop(format!("Extrinsic submitted with hash: {:?}", result));
} else {
display_message("No signed payload received.", false, cli)?;
}
Ok(())
}

// Displays a message to the user, with formatting based on the success status.
fn display_message(message: &str, success: bool, cli: &mut impl Cli) -> Result<()> {
if success {
Expand Down
22 changes: 17 additions & 5 deletions crates/pop-cli/src/commands/up/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use std::path::PathBuf;
mod contract;
#[cfg(feature = "parachain")]
mod network;
#[cfg(feature = "parachain")]
mod parachain;

/// Arguments for launching or deploying a project.
#[derive(Args, Clone)]
Expand All @@ -25,6 +27,10 @@ pub(crate) struct UpArgs {
#[arg(value_name = "PATH", index = 1, global = true, conflicts_with = "path")]
pub path_pos: Option<PathBuf>,

#[command(flatten)]
#[cfg(feature = "parachain")]
pub(crate) parachain: parachain::UpChainCommand,

#[command(flatten)]
#[cfg(feature = "contract")]
pub(crate) contract: contract::UpContractCommand,
Expand Down Expand Up @@ -73,7 +79,9 @@ impl Command {
}
#[cfg(feature = "parachain")]
if pop_parachains::is_supported(project_path.as_deref())? {
cli.warning("Parachain deployment is currently not implemented.")?;
let mut cmd = args.parachain;
cmd.path = project_path;
cmd.execute(cli).await?;
return Ok("parachain");
}
cli.warning(
Expand All @@ -85,7 +93,7 @@ impl Command {

#[cfg(test)]
mod tests {
use super::{contract::UpContractCommand, *};
use super::{contract::UpContractCommand, parachain::UpChainCommand, *};

use cli::MockCli;
use duct::cmd;
Expand Down Expand Up @@ -114,6 +122,7 @@ mod tests {
skip_confirm: false,
valid: false,
},
parachain: UpChainCommand::default(),
command: None,
})
}
Expand Down Expand Up @@ -146,9 +155,12 @@ mod tests {
};
instantiate_template_dir(&Parachain::Standard, &project_path, None, config)?;

let args = create_up_args(project_path)?;
let mut cli =
MockCli::new().expect_warning("Parachain deployment is currently not implemented.");
let mut args = create_up_args(project_path)?;
args.parachain.relay_url = Some(Url::parse("wss://polkadot-rpc.publicnode.com")?);
args.parachain.id = Some(2000);
args.parachain.genesis_code = Some(PathBuf::from("path/to/genesis"));
args.parachain.genesis_state = Some(PathBuf::from("path/to/state"));
let mut cli = MockCli::new();
assert_eq!(Command::execute_project_deployment(args, &mut cli).await?, "parachain");
cli.verify()
}
Expand Down
Loading
Loading