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

fix: hrmp #278

Merged
merged 25 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f032569
chore: switch pop network configuration to paseo with hrmp channels
evilrobot-01 Aug 7, 2024
454da96
test: add relay+asset hub network config files
evilrobot-01 Aug 9, 2024
2363a51
feat: clean dmpq state at genesis (#279)
al3mart Aug 10, 2024
fb3a927
refactor: improve ux
evilrobot-01 Aug 10, 2024
ef662f2
feat: add rococo-local metadata
evilrobot-01 Aug 10, 2024
a1f2502
fix: resolve merge conflict
evilrobot-01 Oct 10, 2024
99df89d
chore: update zombienet-sdk
evilrobot-01 Oct 10, 2024
7d2e1b7
chore: update cargo.lock
evilrobot-01 Nov 27, 2024
22bd076
refactor: use dynamic tx
evilrobot-01 Nov 27, 2024
d2c0b95
docs: add variant doc comment
evilrobot-01 Nov 27, 2024
2c9088c
refactor: address clippy warning
evilrobot-01 Nov 27, 2024
e6c8d4c
chore: remove duplicate dependency after rebase
evilrobot-01 Dec 18, 2024
e73d132
refactor: identify hrmp_channels earlier
evilrobot-01 Dec 18, 2024
ea28f38
test: add supported relay chains test
evilrobot-01 Dec 18, 2024
a41aea6
refactor: use construct_sudo_extrinsic
evilrobot-01 Dec 18, 2024
cdf419d
refactor: split into smaller functions for better testing
evilrobot-01 Dec 18, 2024
cb4dba2
chore: add westend network configs
evilrobot-01 Dec 18, 2024
4a2ccb6
refactor: replace rococo with westend
evilrobot-01 Dec 18, 2024
9bab41b
refactor: remove duplicate import
evilrobot-01 Dec 19, 2024
72c2ec0
refactor: remove unusued parameter
evilrobot-01 Dec 19, 2024
41823ad
refactor: use global import
evilrobot-01 Dec 19, 2024
547f531
fix: update error message
evilrobot-01 Dec 19, 2024
eabb90a
refactor: improve function name
evilrobot-01 Dec 19, 2024
cc84982
refactor: use non-clashing variable name to support global import
evilrobot-01 Dec 19, 2024
863ab92
refactor: reuse spinner
evilrobot-01 Dec 19, 2024
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.

2 changes: 1 addition & 1 deletion crates/pop-cli/src/commands/call/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ impl Call {
},
};
// If sudo is required, wrap the call in a sudo call.
let xt = if self.sudo { construct_sudo_extrinsic(xt)? } else { xt };
let xt = if self.sudo { construct_sudo_extrinsic(xt) } else { xt };
let encoded_data = encode_call_data(client, &xt)?;
// If the encoded call data is too long, don't display it all.
if encoded_data.len() < ENCODED_CALL_DATA_MAX_LEN {
Expand Down
43 changes: 36 additions & 7 deletions crates/pop-cli/src/commands/up/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
use crate::style::{style, Theme};
use clap::Args;
use cliclack::{
clear_screen, confirm, intro, log, multi_progress, outro, outro_cancel, set_theme, ProgressBar,
Theme as _, ThemeState,
clear_screen, confirm, intro, log, multi_progress, outro, outro_cancel, set_theme, spinner,
ProgressBar, Theme as _, ThemeState,
};
use console::{Emoji, Style, Term};
use duct::cmd;
use pop_common::Status;
use pop_parachains::{Error, IndexSet, NetworkNode, Zombienet};
use pop_parachains::{clear_dmpq, Error, IndexSet, NetworkNode, RelayChain, Zombienet};
use std::{path::Path, time::Duration};
use tokio::time::sleep;

Expand Down Expand Up @@ -91,8 +91,8 @@
}

// Finally spawn network and wait for signal to terminate
let spinner = cliclack::spinner();
spinner.start("🚀 Launching local network...");
let progress = spinner();
progress.start("🚀 Launching local network...");
match zombienet.spawn().await {
Ok(network) => {
let mut result =
Expand Down Expand Up @@ -143,10 +143,39 @@
}

if let Some(command) = &self.command {
run_custom_command(&spinner, command).await?;
run_custom_command(&progress, command).await?;
}

progress.stop(result);

// Check for any specified channels
AlexD10S marked this conversation as resolved.
Show resolved Hide resolved
if zombienet.hrmp_channels() {
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 `westend-local`."))?;
},
evilrobot-01 marked this conversation as resolved.
Show resolved Hide resolved
Some(_) => {
let progress = spinner();
progress.start("Connecting to relay chain to prepare channels...");
// Allow relay node time to start
sleep(Duration::from_secs(10)).await;
progress.set_message("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_endpoint, &para_ids).await {
progress.stop(format!("🚫 Could not prepare channels: {e}"));
return Ok::<(), Error>(());
}
progress.stop("Channels successfully prepared for initialization.");
Ok::<(), Error>(())
});
},
}
}

spinner.stop(result);
tokio::signal::ctrl_c().await?;
outro("Done")?;
},
Expand Down Expand Up @@ -255,7 +284,7 @@
let binaries: Vec<_> = binaries
.into_iter()
.filter(|b| !b.exists() || (latest && b.stale()))
.map(|b| {

Check warning on line 287 in crates/pop-cli/src/commands/up/parachain.rs

View workflow job for this annotation

GitHub Actions / clippy

using `map` over `inspect`

warning: using `map` over `inspect` --> crates/pop-cli/src/commands/up/parachain.rs:287:5 | 287 | .map(|b| { | ^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_inspect = note: `#[warn(clippy::manual_inspect)]` on by default help: try | 287 ~ .inspect(|b| { 288 | if latest && b.stale() { 289 | b.use_latest() 290 ~ } |
if latest && b.stale() {
b.use_latest()
}
Expand Down
3 changes: 2 additions & 1 deletion crates/pop-parachains/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ glob.workspace = true
serde_json.workspace = true
strum.workspace = true
strum_macros.workspace = true
subxt-signer.workspace = true
subxt.workspace = true
tar.workspace = true
tempfile.workspace = true
thiserror.workspace = true
Expand All @@ -29,7 +31,6 @@ reqwest.workspace = true
scale-info.workspace = true
scale-value.workspace = true
sp-core.workspace = true
subxt.workspace = true
symlink.workspace = true
toml_edit.workspace = true
walkdir.workspace = true
Expand Down
6 changes: 3 additions & 3 deletions crates/pop-parachains/src/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ pub fn construct_extrinsic(
/// # Arguments
/// * `xt`: The extrinsic representing the dispatchable function call to be dispatched with `Root`
/// privileges.
pub fn construct_sudo_extrinsic(xt: DynamicPayload) -> Result<DynamicPayload, Error> {
Ok(subxt::dynamic::tx("Sudo", "sudo", [xt.into_value()].to_vec()))
pub fn construct_sudo_extrinsic(xt: DynamicPayload) -> DynamicPayload {
subxt::dynamic::tx("Sudo", "sudo", [xt.into_value()].to_vec())
}

/// Signs and submits a given extrinsic.
Expand Down Expand Up @@ -255,7 +255,7 @@ mod tests {
"100".to_string(),
],
)?;
let xt = construct_sudo_extrinsic(xt)?;
let xt = construct_sudo_extrinsic(xt);
assert_eq!(xt.call_name(), "sudo");
assert_eq!(xt.pallet_name(), "Sudo");
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions crates/pop-parachains/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#[derive(Error, Debug)]
pub enum Error {
#[error("User aborted due to existing target directory.")]
Aborted,

Check warning on line 10 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:10:2 | 10 | Aborted, | ^^^^^^^ | = note: requested on the command line with `-W missing-docs`
#[error("Anyhow error: {0}")]
AnyhowError(#[from] anyhow::Error),

Check warning on line 12 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:12:2 | 12 | AnyhowError(#[from] anyhow::Error), | ^^^^^^^^^^^
/// An error occurred while decoding the call data.
#[error("Failed to decode call data. {0}")]
CallDataDecodingError(String),
Expand All @@ -17,16 +17,16 @@
#[error("Failed to encode call data. {0}")]
CallDataEncodingError(String),
#[error("{0}")]
CommonError(#[from] pop_common::Error),

Check warning on line 20 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:20:2 | 20 | CommonError(#[from] pop_common::Error), | ^^^^^^^^^^^
/// An error occurred while attempting to establish a connection to the endpoint.
#[error("Failed to establish a connection to: {0}")]
ConnectionFailure(String),
#[error("Configuration error: {0}")]
Config(String),

Check warning on line 25 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:25:2 | 25 | Config(String), | ^^^^^^
#[error("Failed to access the current directory")]
CurrentDirAccess,

Check warning on line 27 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:27:2 | 27 | CurrentDirAccess, | ^^^^^^^^^^^^^^^^
#[error("Failed to parse the endowment value")]
EndowmentError,

Check warning on line 29 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:29:2 | 29 | EndowmentError, | ^^^^^^^^^^^^^^
/// An error occurred during the submission of an extrinsic.
#[error("Extrinsic submission error: {0}")]
ExtrinsicSubmissionError(String),
Expand All @@ -34,22 +34,22 @@
#[error("The dispatchable function is not supported")]
FunctionNotSupported,
#[error("IO error: {0}")]
IO(#[from] std::io::Error),

Check warning on line 37 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:37:2 | 37 | IO(#[from] std::io::Error), | ^^
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),

Check warning on line 39 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:39:2 | 39 | JsonError(#[from] serde_json::Error), | ^^^^^^^^^
/// An error occurred while parsing metadata of a parameter.
#[error("Error parsing metadata for parameter {0}")]
MetadataParsingError(String),
#[error("Missing binary: {0}")]
MissingBinary(String),

Check warning on line 44 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:44:2 | 44 | MissingBinary(String), | ^^^^^^^^^^^^^
#[error("Missing chain spec file at: {0}")]
MissingChainSpec(String),

Check warning on line 46 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:46:2 | 46 | MissingChainSpec(String), | ^^^^^^^^^^^^^^^^
#[error("Command {command} doesn't exist in binary {binary}")]
MissingCommand { command: String, binary: String },

Check warning on line 48 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a struct field

warning: missing documentation for a struct field --> crates/pop-parachains/src/errors.rs:48:36 | 48 | MissingCommand { command: String, binary: String }, | ^^^^^^^^^^^^^^

Check warning on line 48 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a struct field

warning: missing documentation for a struct field --> crates/pop-parachains/src/errors.rs:48:19 | 48 | MissingCommand { command: String, binary: String }, | ^^^^^^^^^^^^^^^

Check warning on line 48 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:48:2 | 48 | MissingCommand { command: String, binary: String }, | ^^^^^^^^^^^^^^
#[error("Orchestrator error: {0}")]
OrchestratorError(#[from] OrchestratorError),

Check warning on line 50 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:50:2 | 50 | OrchestratorError(#[from] OrchestratorError), | ^^^^^^^^^^^^^^^^^
#[error("Failed to create pallet directory")]
PalletDirCreation,

Check warning on line 52 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:52:2 | 52 | PalletDirCreation, | ^^^^^^^^^^^^^^^^^
/// The specified pallet could not be found.
#[error("Failed to find the pallet {0}")]
PalletNotFound(String),
Expand All @@ -57,15 +57,18 @@
#[error("Failed to process the arguments provided by the user.")]
ParamProcessingError,
#[error("Invalid path")]
PathError,

Check warning on line 60 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:60:2 | 60 | PathError, | ^^^^^^^^^
#[error("Failed to execute rustfmt")]
RustfmtError(std::io::Error),

Check warning on line 62 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:62:2 | 62 | RustfmtError(std::io::Error), | ^^^^^^^^^^^^
#[error("Template error: {0}")]
SourcingError(#[from] pop_common::sourcing::Error),

Check warning on line 64 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:64:2 | 64 | SourcingError(#[from] pop_common::sourcing::Error), | ^^^^^^^^^^^^^
/// An error occurred whilst interacting with a chain using `subxt`.
#[error("Subxt error: {0}")]
SubXtError(#[from] subxt::Error),
#[error("Toml error: {0}")]
TomlError(#[from] toml_edit::de::Error),

Check warning on line 69 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:69:2 | 69 | TomlError(#[from] toml_edit::de::Error), | ^^^^^^^^^
#[error("Unsupported command: {0}")]
UnsupportedCommand(String),

Check warning on line 71 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:71:2 | 71 | UnsupportedCommand(String), | ^^^^^^^^^^^^^^^^^^
#[error("Failed to locate the workspace")]
WorkspaceLocate,

Check warning on line 73 in crates/pop-parachains/src/errors.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a variant

warning: missing documentation for a variant --> crates/pop-parachains/src/errors.rs:73:2 | 73 | WorkspaceLocate, | ^^^^^^^^^^^^^^^
}
2 changes: 2 additions & 0 deletions crates/pop-parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod errors;
mod generator;
mod new_pallet;
mod new_parachain;
mod relay;
mod templates;
mod up;
mod utils;
Expand All @@ -30,6 +31,7 @@ pub use errors::Error;
pub use indexmap::IndexSet;
pub use new_pallet::{create_pallet_template, new_pallet_options::*, TemplatePalletConfig};
pub use new_parachain::instantiate_template_dir;
pub use relay::{clear_dmpq, RelayChain};
// External export from subxt.
pub use subxt::{
tx::{DynamicPayload, Payload},
Expand Down
146 changes: 146 additions & 0 deletions crates/pop-parachains/src/relay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-3.0

use crate::{call, DynamicPayload, Error};
use sp_core::twox_128;
use subxt::{
config::BlockHash,
dynamic::{self, Value},
ext::sp_core,
OnlineClient, PolkadotConfig,
};

/// Clears the DMPQ state for the given parachain IDs.
///
/// # 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<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 clear_dmq_keys = generate_storage_keys(para_ids);

// Submit calls to remove specified keys
let kill_storage = construct_kill_storage_call(clear_dmq_keys);
let sudo = subxt_signer::sr25519::dev::alice();
let sudo_call = call::construct_sudo_extrinsic(kill_storage);
Ok(client.tx().sign_and_submit_default(&sudo_call, &sudo).await?)
}

fn construct_kill_storage_call(keys: Vec<Vec<u8>>) -> DynamicPayload {
dynamic::tx(
"System",
"kill_storage",
vec![Value::unnamed_composite(keys.into_iter().map(Value::from_bytes))],
)
}

fn generate_storage_keys(para_ids: &[u32]) -> Vec<Vec<u8>> {
let dmp = twox_128("Dmp".as_bytes());
let dmp_queue_heads = twox_128("DownwardMessageQueueHeads".as_bytes());
let dmp_queues = twox_128("DownwardMessageQueues".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);
}
clear_dmq_keys
}

/// A supported relay chain.
#[derive(Debug, PartialEq)]
pub enum RelayChain {
/// Paseo.
PaseoLocal,
/// Westend.
WestendLocal,
}

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),
"westend-local" => Some(RelayChain::WestendLocal),
_ => None,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use subxt::ext::sp_core::twox_64;
use RelayChain::*;

#[test]
fn construct_kill_storage_call_works() {
let keys = vec!["key".as_bytes().to_vec()];
assert_eq!(
construct_kill_storage_call(keys.clone()),
dynamic::tx(
"System",
"kill_storage",
vec![Value::unnamed_composite(keys.into_iter().map(Value::from_bytes))],
)
)
}

#[test]
fn generate_storage_keys_works() {
let para_ids = vec![1_000, 4_385];
let dmp = twox_128("Dmp".as_bytes());
let dmp_queue_heads = [dmp, twox_128("DownwardMessageQueueHeads".as_bytes())].concat();
let dmp_queues = [dmp, twox_128("DownwardMessageQueues".as_bytes())].concat();

assert_eq!(
generate_storage_keys(&para_ids),
para_ids
.iter()
.flat_map(|id| {
let id = id.to_le_bytes().to_vec();
[
// DMP Queue Head
[dmp_queue_heads.clone(), twox_64(&id).to_vec(), id.clone()].concat(),
// DMP Queue
[dmp_queues.clone(), twox_64(&id).to_vec(), id].concat(),
]
})
.collect::<Vec<_>>()
)
}

#[test]
fn supported_relay_chains() {
for (s, e) in [
// Only chains with sudo supported
("paseo-local", Some(PaseoLocal)),
("westend-local", Some(WestendLocal)),
("kusama-local", None),
("polkadot-local", None),
] {
assert_eq!(RelayChain::from(s), e)
}
}
}
Loading
Loading