Skip to content

Commit

Permalink
refactor: improve ux
Browse files Browse the repository at this point in the history
  • Loading branch information
evilrobot-01 committed Aug 10, 2024
1 parent 6130384 commit 6beb4ba
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 83 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

49 changes: 30 additions & 19 deletions crates/pop-cli/src/commands/up/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use cliclack::{
use console::{Emoji, Style, Term};
use duct::cmd;
use pop_common::Status;
use pop_parachains::{clear_dmpq, Error, IndexSet, NetworkNode, Zombienet};
use pop_parachains::{clear_dmpq, Error, IndexSet, NetworkNode, RelayChain, Zombienet};
use std::{path::PathBuf, time::Duration};
use tokio::time::sleep;

Expand Down Expand Up @@ -149,25 +149,36 @@ impl ZombienetCommand {

spinner.stop(result);

// Check for any HRMP specified channels
// Check for any specified channels
if zombienet.hrmp_channels() {
let spinner = cliclack::spinner();
spinner.start("Readying channels...");
// Allow relay node time to start
tokio::time::sleep(Duration::from_secs(10)).await;
let relay_endpoint = network.relaychain().nodes()[0].client().await?;
let para_ids: Vec<_> =
network.parachains().iter().map(|p| p.para_id()).collect();
tokio::spawn(async move {
if let Err(e) = clear_dmpq(relay_endpoint, &para_ids).await {
spinner.stop("");
outro_cancel(format!("{e}"))?;
}
spinner.stop("Channels ready for initialization.");
tokio::time::sleep(Duration::from_secs(2)).await;
Term::stderr().clear_last_lines(2)?;
Ok::<(), Error>(())
});
let relay_chain = zombienet.relay_chain();
match RelayChain::from(relay_chain) {
None => {
log::error(format!("🚫 Using `{relay_chain}` with HRMP channels is currently unsupported. Please use `paseo-local` or `rococo-local`."))?;
},
Some(relay_chain) => {
use tokio::time::sleep;
let spinner = cliclack::spinner();
spinner.start("Connecting to relay chain to prepare channels...");
// Allow relay node time to start
sleep(Duration::from_secs(10)).await;
spinner.start("Preparing channels...");
let relay_endpoint = network.relaychain().nodes()[0].client().await?;
let para_ids: Vec<_> =
network.parachains().iter().map(|p| p.para_id()).collect();
tokio::spawn(async move {
if let Err(e) =
clear_dmpq(relay_chain, relay_endpoint, &para_ids).await
{
spinner.stop("");
log::error(format!("🚫 Could not prepare channels: {e}"))?;
return Ok::<(), Error>(());
}
spinner.stop("Channels successfully prepared for initialization.");
Ok::<(), Error>(())
});
},
}
}

tokio::signal::ctrl_c().await?;
Expand Down
2 changes: 2 additions & 0 deletions crates/pop-parachains/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum Error {
RustfmtError(std::io::Error),
#[error("Template error: {0}")]
SourcingError(#[from] pop_common::sourcing::Error),
#[error("Subxt error: {0}")]
SubXtError(#[from] subxt::Error),
#[error("Toml error: {0}")]
TomlError(#[from] toml_edit::de::Error),
#[error("Unsupported command: {0}")]
Expand Down
4 changes: 3 additions & 1 deletion crates/pop-parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod errors;
mod generator;
mod new_pallet;
mod new_parachain;
mod relay;
mod templates;
mod up;
mod utils;
Expand All @@ -18,9 +19,10 @@ pub use errors::Error;
pub use indexmap::IndexSet;
pub use new_pallet::{create_pallet_template, TemplatePalletConfig};
pub use new_parachain::instantiate_template_dir;
pub use relay::{clear_dmpq, RelayChain};
pub use templates::{Config, Parachain, Provider};
pub use up::Zombienet;
pub use utils::helpers::{clear_dmpq, is_initial_endowment_valid};
pub use utils::helpers::is_initial_endowment_valid;
pub use utils::pallet_helpers::resolve_pallet_path;
/// Information about the Node. External export from Zombienet-SDK.
pub use zombienet_sdk::NetworkNode;
93 changes: 93 additions & 0 deletions crates/pop-parachains/src/relay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-3.0

use crate::Error;
use sp_core::twox_128;
use subxt::{config::BlockHash, ext::sp_core, OnlineClient, PolkadotConfig};

/// Clears the DMPQ state for the given parachain IDs.
///
/// # Arguments
/// * `relay_chain` - The relay chain.
/// * `client` - Client for the network which state is to be modified.
/// * `para_ids` - List of ids to build the keys that will be mutated.
pub async fn clear_dmpq(
relay_chain: RelayChain,
client: OnlineClient<PolkadotConfig>,
para_ids: &[u32],
) -> Result<impl BlockHash, Error> {
// Wait for blocks to be produced.
let mut sub = client.blocks().subscribe_finalized().await?;
for _ in 0..2 {
sub.next().await;
}

// Generate storage keys to be removed
let dmp = twox_128("Dmp".as_bytes());
let dmp_queues = twox_128("DownwardMessageQueues".as_bytes());
let dmp_queue_heads = twox_128("DownwardMessageQueueHeads".as_bytes());
let mut clear_dmq_keys = Vec::<Vec<u8>>::new();
for id in para_ids {
let id = id.to_le_bytes();
// DMP Queue Head
let mut key = dmp.to_vec();
key.extend(&dmp_queue_heads);
key.extend(sp_core::twox_64(&id));
key.extend(id);
clear_dmq_keys.push(key);
// DMP Queue
let mut key = dmp.to_vec();
key.extend(&dmp_queues);
key.extend(sp_core::twox_64(&id));
key.extend(id);
clear_dmq_keys.push(key);
}

// Submit calls to remove specified keys
let sudo = subxt_signer::sr25519::dev::alice();
match relay_chain {
RelayChain::PaseoLocal => {
use paseo_local::{
runtime_types::paseo_runtime::RuntimeCall::System, system::Call, tx,
};
let sudo_call = tx().sudo().sudo(System(Call::kill_storage { keys: clear_dmq_keys }));
Ok(client.tx().sign_and_submit_default(&sudo_call, &sudo).await?)
},
RelayChain::RococoLocal => {
use rococo_local::{
runtime_types::rococo_runtime::RuntimeCall::System, system::Call, tx,
};
let sudo_call = tx().sudo().sudo(System(Call::kill_storage { keys: clear_dmq_keys }));
Ok(client.tx().sign_and_submit_default(&sudo_call, &sudo).await?)
},
}
}

/// A supported relay chain.
pub enum RelayChain {
/// Paseo.
PaseoLocal,
/// Rococo.
RococoLocal,
}

impl RelayChain {
/// Attempts to convert a chain identifier into a supported `RelayChain` variant.
///
/// # Arguments
/// * `id` - The relay chain identifier.
pub fn from(id: &str) -> Option<RelayChain> {
match id {
"paseo-local" => Some(RelayChain::PaseoLocal),
"rococo-local" => Some(RelayChain::RococoLocal),
_ => None,
}
}
}

// subxt metadata --url ws://127.0.0.1:58774 --pallets System,Sudo > paseo-local.scale
#[subxt::subxt(runtime_metadata_path = "./src/utils/artifacts/paseo-local.scale")]
mod paseo_local {}

// subxt metadata --url ws://127.0.0.1:58774 --pallets System,Sudo > rococo-local.scale
#[subxt::subxt(runtime_metadata_path = "./src/utils/artifacts/rococo-local.scale")]
mod rococo_local {}
11 changes: 8 additions & 3 deletions crates/pop-parachains/src/up/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl Zombienet {
// Parse network config
let network_config = NetworkConfiguration::from(network_config)?;
// Determine relay and parachain requirements based on arguments and config
let relay_chain = Self::relay_chain(
let relay_chain = Self::_relay_chain(
relay_chain_version,
relay_chain_runtime_version,
&network_config,
Expand Down Expand Up @@ -209,7 +209,7 @@ impl Zombienet {
/// * `runtime_version` - The specific runtime version used for the relay chain runtime (`None` will use the latest available version).
/// * `network_config` - The network configuration to be used to launch a network.
/// * `cache` - The location used for caching binaries.
async fn relay_chain(
async fn _relay_chain(
version: Option<&str>,
runtime_version: Option<&str>,
network_config: &NetworkConfiguration,
Expand Down Expand Up @@ -267,7 +267,12 @@ impl Zombienet {
}
}
// Otherwise use default
return Ok(relay::default(version, runtime_version, chain, cache).await?);
Ok(relay::default(version, runtime_version, chain, cache).await?)
}

/// The name of the relay chain.
pub fn relay_chain(&self) -> &str {
&self.relay_chain.chain
}

/// Whether any HRMP channels are to be pre-opened.
Expand Down
62 changes: 2 additions & 60 deletions crates/pop-parachains/src/utils/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::{
io::{self, stdin, stdout, Write},
path::Path,
};
use subxt::{ext::sp_core, OnlineClient, PolkadotConfig};

pub(crate) fn sanitize(target: &Path) -> Result<(), Error> {
if target.exists() {
Expand All @@ -25,64 +24,6 @@ pub(crate) fn sanitize(target: &Path) -> Result<(), Error> {
Ok(())
}

/// Clears the DMPQ state for the given chains.
/// Assumes pallet-sudo is present in the runtime.
///
/// # Arguments
///
/// * `client` - Client for the network which state is to be modified.
/// * `para_ids` - List of ids to build the keys that will be mutated.
pub async fn clear_dmpq(
client: OnlineClient<PolkadotConfig>,
para_ids: &[u32],
) -> Result<(), Box<dyn std::error::Error>> {
use subxt_signer::sr25519::dev;

#[subxt::subxt(runtime_metadata_path = "./src/utils/artifacts/paseo-local.scale")]
mod paseo_local {}
type RuntimeCall = paseo_local::runtime_types::paseo_runtime::RuntimeCall;

let sudo = dev::alice();

// Wait for blocks to be produced.
let mut sub = client.blocks().subscribe_finalized().await.unwrap();
for _ in 0..2 {
sub.next().await;
}

let dmp = sp_core::twox_128("Dmp".as_bytes());
let dmp_queues = sp_core::twox_128("DownwardMessageQueues".as_bytes());
let dmp_queue_heads = sp_core::twox_128("DownwardMessageQueueHeads".as_bytes());

let mut clear_dmq_keys = Vec::<Vec<u8>>::new();
for id in para_ids {
let id = id.to_le_bytes();
// DMP Queue Head
let mut key = dmp.to_vec();
key.extend(&dmp_queue_heads);
key.extend(sp_core::twox_64(&id));
key.extend(id);
clear_dmq_keys.push(key);
// DMP Queue
let mut key = dmp.to_vec();
key.extend(&dmp_queues);
key.extend(sp_core::twox_64(&id));
key.extend(id);
clear_dmq_keys.push(key);
}

// Craft calls to dispatch
let kill_storage =
RuntimeCall::System(paseo_local::system::Call::kill_storage { keys: clear_dmq_keys });
let sudo_call = paseo_local::tx().sudo().sudo(kill_storage);

// Dispatch and watch tx
let _sudo_call_events =
client.tx().sign_and_submit_then_watch_default(&sudo_call, &sudo).await?;

Ok(())
}

/// Check if the initial endowment input by the user is a valid balance.
///
/// # Arguments
Expand All @@ -92,7 +33,8 @@ pub fn is_initial_endowment_valid(initial_endowment: &str) -> bool {
initial_endowment.parse::<u128>().is_ok()
|| is_valid_bitwise_left_shift(initial_endowment).is_ok()
}
// Auxiliar method to check if the endowment input with a shift left (1u64 << 60) format is valid.

// Auxiliary method to check if the endowment input with a shift left (1u64 << 60) format is valid.
// Parse the self << rhs format and check the shift left operation is valid.
fn is_valid_bitwise_left_shift(initial_endowment: &str) -> Result<u128, Error> {
let v: Vec<&str> = initial_endowment.split(" << ").collect();
Expand Down

0 comments on commit 6beb4ba

Please sign in to comment.