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: add parachains to a running network #142

Merged
merged 5 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion crates/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ mod utils;
pub use global_settings::{GlobalSettings, GlobalSettingsBuilder};
pub use hrmp_channel::{HrmpChannelConfig, HrmpChannelConfigBuilder};
pub use network::{NetworkConfig, NetworkConfigBuilder};
pub use parachain::{ParachainConfig, ParachainConfigBuilder, RegistrationStrategy};
pub use parachain::{
states as para_states, ParachainConfig, ParachainConfigBuilder, RegistrationStrategy,
};
pub use relaychain::{RelaychainConfig, RelaychainConfigBuilder};
// re-export shared
pub use shared::{node::NodeConfig, types};
7 changes: 5 additions & 2 deletions crates/configuration/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,11 @@ impl NetworkConfigBuilder<WithRelaychain> {
pub fn with_parachain(
self,
f: fn(
ParachainConfigBuilder<parachain::Initial>,
) -> ParachainConfigBuilder<parachain::WithAtLeastOneCollator>,
ParachainConfigBuilder<parachain::states::Initial, parachain::states::Bootstrap>,
) -> ParachainConfigBuilder<
parachain::states::WithAtLeastOneCollator,
parachain::states::Bootstrap,
>,
) -> Self {
match f(ParachainConfigBuilder::new(self.validation_context.clone())).build() {
Ok(parachain) => Self::transition(
Expand Down
105 changes: 78 additions & 27 deletions crates/configuration/src/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::{
shared::{
errors::{ConfigError, FieldError},
helpers::{merge_errors, merge_errors_vecs},
macros::states,
node::{self, NodeConfig, NodeConfigBuilder},
resources::{Resources, ResourcesBuilder},
types::{
Expand Down Expand Up @@ -224,21 +223,36 @@ impl ParachainConfig {
}
}

states! {
Initial,
WithId,
WithAtLeastOneCollator
pub mod states {
use crate::shared::macros::states;

states! {
Initial,
WithId,
WithAtLeastOneCollator
}

states! {
Bootstrap,
Running
}

pub trait Context {}
impl Context for Bootstrap {}
impl Context for Running {}
}

use states::{Bootstrap, Context, Initial, Running, WithAtLeastOneCollator, WithId};
/// A parachain configuration builder, used to build a [`ParachainConfig`] declaratively with fields validation.
pub struct ParachainConfigBuilder<S> {
pub struct ParachainConfigBuilder<S, C> {
config: ParachainConfig,
validation_context: Rc<RefCell<ValidationContext>>,
errors: Vec<anyhow::Error>,
_state: PhantomData<S>,
_context: PhantomData<C>,
}

impl Default for ParachainConfigBuilder<Initial> {
impl<C: Context> Default for ParachainConfigBuilder<Initial, C> {
fn default() -> Self {
Self {
config: ParachainConfig {
Expand All @@ -265,21 +279,23 @@ impl Default for ParachainConfigBuilder<Initial> {
validation_context: Default::default(),
errors: vec![],
_state: PhantomData,
_context: PhantomData,
}
}
}

impl<A> ParachainConfigBuilder<A> {
impl<A, C> ParachainConfigBuilder<A, C> {
fn transition<B>(
config: ParachainConfig,
validation_context: Rc<RefCell<ValidationContext>>,
errors: Vec<anyhow::Error>,
) -> ParachainConfigBuilder<B> {
) -> ParachainConfigBuilder<B, C> {
ParachainConfigBuilder {
config,
validation_context,
errors,
_state: PhantomData,
_context: PhantomData,
}
}

Expand All @@ -294,19 +310,51 @@ impl<A> ParachainConfigBuilder<A> {
}
}

impl ParachainConfigBuilder<Initial> {
impl ParachainConfigBuilder<Initial, Bootstrap> {
pub fn new(
validation_context: Rc<RefCell<ValidationContext>>,
) -> ParachainConfigBuilder<Initial> {
) -> ParachainConfigBuilder<Initial, Bootstrap> {
Self {
validation_context,
..Self::default()
}
}
}

impl ParachainConfigBuilder<WithId, Bootstrap> {
/// Set the registration strategy for the parachain, could be without registration, using extrinsic or in genesis.
pub fn with_registration_strategy(self, strategy: RegistrationStrategy) -> Self {
Self::transition(
ParachainConfig {
registration_strategy: Some(strategy),
..self.config
},
self.validation_context,
self.errors,
)
}
}

impl ParachainConfigBuilder<Initial, Running> {
/// Start a new builder in the context of a running network
pub fn new_with_running(
validation_context: Rc<RefCell<ValidationContext>>,
) -> ParachainConfigBuilder<Initial, Running> {
let mut builder = Self {
validation_context,
..Self::default()
};

// override the registration strategy
builder.config.registration_strategy = Some(RegistrationStrategy::UsingExtrinsic);
builder
}
}

impl<C: Context> ParachainConfigBuilder<Initial, C> {
/// Set the parachain ID (should be unique).
// TODO: handle unique validation
pub fn with_id(self, id: u32) -> ParachainConfigBuilder<WithId> {
pub fn with_id(self, id: u32) -> ParachainConfigBuilder<WithId, C> {
Self::transition(
ParachainConfig { id, ..self.config },
self.validation_context,
Expand All @@ -315,7 +363,7 @@ impl ParachainConfigBuilder<Initial> {
}
}

impl ParachainConfigBuilder<WithId> {
impl<C: Context> ParachainConfigBuilder<WithId, C> {
/// Set the chain name (e.g. rococo-local).
/// Use [`None`], if you are running adder-collator or undying-collator).
pub fn with_chain<T>(self, chain: T) -> Self
Expand All @@ -340,18 +388,6 @@ impl ParachainConfigBuilder<WithId> {
}
}

/// Set the registration strategy for the parachain, could be without registration, using extrinsic or in genesis.
pub fn with_registration_strategy(self, strategy: RegistrationStrategy) -> Self {
Self::transition(
ParachainConfig {
registration_strategy: Some(strategy),
..self.config
},
self.validation_context,
self.errors,
)
}

/// Set whether the parachain should be onboarded or stay a parathread. Default is ```true```.
pub fn onboard_as_parachain(self, choice: bool) -> Self {
Self::transition(
Expand Down Expand Up @@ -615,7 +651,7 @@ impl ParachainConfigBuilder<WithId> {
pub fn with_collator(
self,
f: fn(NodeConfigBuilder<node::Initial>) -> NodeConfigBuilder<node::Buildable>,
) -> ParachainConfigBuilder<WithAtLeastOneCollator> {
) -> ParachainConfigBuilder<WithAtLeastOneCollator, C> {
match f(NodeConfigBuilder::new(
self.default_chain_context(),
self.validation_context.clone(),
Expand Down Expand Up @@ -645,7 +681,7 @@ impl ParachainConfigBuilder<WithId> {
}
}

impl ParachainConfigBuilder<WithAtLeastOneCollator> {
impl<C: Context> ParachainConfigBuilder<WithAtLeastOneCollator, C> {
/// Add a new collator using a nested [`NodeConfigBuilder`].
pub fn with_collator(
self,
Expand Down Expand Up @@ -1122,4 +1158,19 @@ mod tests {

assert!(config.onboard_as_parachain());
}

#[test]
fn build_config_in_running_context() {
let config = ParachainConfigBuilder::new_with_running(Default::default())
.with_id(2000)
.with_chain("myparachain")
.with_collator(|collator| collator.with_name("collator"))
.build()
.unwrap();

assert_eq!(
config.registration_strategy(),
Some(&RegistrationStrategy::UsingExtrinsic)
);
}
}
10 changes: 5 additions & 5 deletions crates/configuration/src/shared/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ use crate::{
utils::{default_as_true, default_initial_balance},
};

states! {
Buildable,
Initial
}

/// An environment variable with a name and a value.
/// It can be constructed from a `(&str, &str)`.
///
Expand Down Expand Up @@ -245,11 +250,6 @@ impl NodeConfig {
}
}

states! {
Initial,
Buildable
}

/// A node configuration builder, used to build a [`NodeConfig`] declaratively with fields validation.
pub struct NodeConfigBuilder<S> {
config: NodeConfig,
Expand Down
1 change: 1 addition & 0 deletions crates/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ futures = { workspace = true }
subxt = { workspace = true }
tracing-subscriber = "0.3"
serde_json = { workspace = true }
anyhow = { workspace = true }
51 changes: 51 additions & 0 deletions crates/examples/examples/add_para.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use anyhow::anyhow;
use futures::stream::StreamExt;
use zombienet_sdk::{NetworkConfigBuilder, NetworkConfigExt};

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
tracing_subscriber::fmt::init();
let mut network = NetworkConfigBuilder::new()
.with_relaychain(|r| {
r.with_chain("rococo-local")
.with_default_command("polkadot")
.with_node(|node| node.with_name("alice"))
.with_node(|node| node.with_name("bob"))
})
.build()
.unwrap()
.spawn_native()
.await?;

println!("🚀🚀🚀🚀 network deployed");

let alice = network.get_node("alice")?;
let client = alice.client::<subxt::PolkadotConfig>().await?;

// wait 3 blocks
let mut blocks = client.blocks().subscribe_finalized().await?.take(3);

while let Some(block) = blocks.next().await {
println!("Block #{}", block?.header().number);
}

println!("⚙️ adding parachain to the running network");

let para_config = network
.para_config_builder()
.with_id(100)
.with_default_command("polkadot-parachain")
.with_collator(|c| c.with_name("col-100-1"))
.build()
.map_err(|_e| anyhow!("Building config"))?;

network.add_parachain(&para_config, None).await?;

// For now let just loop....
#[allow(clippy::empty_loop)]
loop {}

#[allow(clippy::unreachable)]
#[allow(unreachable_code)]
Ok(())
}
38 changes: 22 additions & 16 deletions crates/orchestrator/src/generators/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,22 +213,7 @@ impl ChainSpec {
T: FileSystem,
{
let (content, _) = self.read_spec(scoped_fs).await?;
let chain_spec_json: serde_json::Value = serde_json::from_str(&content).map_err(|_| {
GeneratorError::ChainSpecGeneration("Can not parse chain-spec as json".into())
})?;
if let Some(chain_id) = chain_spec_json.get("id") {
if let Some(chain_id) = chain_id.as_str() {
Ok(chain_id.to_string())
} else {
Err(GeneratorError::ChainSpecGeneration(
"id should be an string in the chain-spec, this is a bug".into(),
))
}
} else {
Err(GeneratorError::ChainSpecGeneration(
"'id' should be a fields in the chain-spec of the relaychain".into(),
))
}
ChainSpec::chain_id_from_spec(&content)
}

async fn read_spec<'a, T>(
Expand Down Expand Up @@ -511,6 +496,27 @@ impl ChainSpec {

Ok(())
}

/// Get the chain_is from the json content of a chain-spec file.
pub fn chain_id_from_spec(spec_content: &str) -> Result<String, GeneratorError> {
let chain_spec_json: serde_json::Value =
serde_json::from_str(spec_content).map_err(|_| {
GeneratorError::ChainSpecGeneration("Can not parse chain-spec as json".into())
})?;
if let Some(chain_id) = chain_spec_json.get("id") {
if let Some(chain_id) = chain_id.as_str() {
Ok(chain_id.to_string())
} else {
Err(GeneratorError::ChainSpecGeneration(
"id should be an string in the chain-spec, this is a bug".into(),
))
}
} else {
Err(GeneratorError::ChainSpecGeneration(
"'id' should be a fields in the chain-spec of the relaychain".into(),
))
}
}
}

type GenesisNodeKey = (String, String, HashMap<String, String>);
Expand Down
Loading