fix: migrate vendor rustfmt.toml to stable-only features

- Update vendor/pezkuwi-zombienet-sdk/rustfmt.toml to stable-only
- Reformat 74 vendor files with stable rustfmt
- Remove nightly-only features causing CI failures
This commit is contained in:
2025-12-23 10:00:48 +03:00
parent 9bfa143337
commit ebd8fafdee
74 changed files with 19895 additions and 21681 deletions
+3 -1
View File
@@ -302,7 +302,9 @@ impl<T: Config> ExtrinsicEvents<T> {
/// ///
/// This works in the same way that [`events::Events::find()`] does, with the /// This works in the same way that [`events::Events::find()`] does, with the
/// exception that it filters out events not related to the submitted extrinsic. /// exception that it filters out events not related to the submitted extrinsic.
pub fn find<'a, Ev: events::StaticEvent + 'a>(&'a self) -> impl Iterator<Item = Result<Ev, EventsError>> + 'a { pub fn find<'a, Ev: events::StaticEvent + 'a>(
&'a self,
) -> impl Iterator<Item = Result<Ev, EventsError>> + 'a {
self.iter().filter_map(|ev| ev.and_then(|ev| ev.as_event::<Ev>()).transpose()) self.iter().filter_map(|ev| ev.and_then(|ev| ev.as_event::<Ev>()).transpose())
} }
@@ -137,10 +137,7 @@ impl GlobalSettingsBuilder {
} }
Self::transition( Self::transition(
GlobalSettings { GlobalSettings { bootnodes_addresses: addrs, ..self.config },
bootnodes_addresses: addrs,
..self.config
},
merge_errors_vecs(self.errors, errors), merge_errors_vecs(self.errors, errors),
) )
} }
@@ -148,33 +145,21 @@ impl GlobalSettingsBuilder {
/// Set global spawn timeout in seconds. /// Set global spawn timeout in seconds.
pub fn with_network_spawn_timeout(self, timeout: Duration) -> Self { pub fn with_network_spawn_timeout(self, timeout: Duration) -> Self {
Self::transition( Self::transition(
GlobalSettings { GlobalSettings { network_spawn_timeout: timeout, ..self.config },
network_spawn_timeout: timeout,
..self.config
},
self.errors, self.errors,
) )
} }
/// Set individual node spawn timeout in seconds. /// Set individual node spawn timeout in seconds.
pub fn with_node_spawn_timeout(self, timeout: Duration) -> Self { pub fn with_node_spawn_timeout(self, timeout: Duration) -> Self {
Self::transition( Self::transition(GlobalSettings { node_spawn_timeout: timeout, ..self.config }, self.errors)
GlobalSettings {
node_spawn_timeout: timeout,
..self.config
},
self.errors,
)
} }
/// Set local IP used to expose local services (including RPC, metrics and monitoring). /// Set local IP used to expose local services (including RPC, metrics and monitoring).
pub fn with_local_ip(self, local_ip: &str) -> Self { pub fn with_local_ip(self, local_ip: &str) -> Self {
match IpAddr::from_str(local_ip) { match IpAddr::from_str(local_ip) {
Ok(local_ip) => Self::transition( Ok(local_ip) => Self::transition(
GlobalSettings { GlobalSettings { local_ip: Some(local_ip), ..self.config },
local_ip: Some(local_ip),
..self.config
},
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
@@ -187,10 +172,7 @@ impl GlobalSettingsBuilder {
/// Set the directory to use as base (instead of a random tmp one). /// Set the directory to use as base (instead of a random tmp one).
pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self { pub fn with_base_dir(self, base_dir: impl Into<PathBuf>) -> Self {
Self::transition( Self::transition(
GlobalSettings { GlobalSettings { base_dir: Some(base_dir.into()), ..self.config },
base_dir: Some(base_dir.into()),
..self.config
},
self.errors, self.errors,
) )
} }
@@ -198,23 +180,14 @@ impl GlobalSettingsBuilder {
/// Set the spawn concurrency /// Set the spawn concurrency
pub fn with_spawn_concurrency(self, spawn_concurrency: usize) -> Self { pub fn with_spawn_concurrency(self, spawn_concurrency: usize) -> Self {
Self::transition( Self::transition(
GlobalSettings { GlobalSettings { spawn_concurrency: Some(spawn_concurrency), ..self.config },
spawn_concurrency: Some(spawn_concurrency),
..self.config
},
self.errors, self.errors,
) )
} }
/// Set the `tear_down_on_failure` flag /// Set the `tear_down_on_failure` flag
pub fn with_tear_down_on_failure(self, tear_down_on_failure: bool) -> Self { pub fn with_tear_down_on_failure(self, tear_down_on_failure: bool) -> Self {
Self::transition( Self::transition(GlobalSettings { tear_down_on_failure, ..self.config }, self.errors)
GlobalSettings {
tear_down_on_failure,
..self.config
},
self.errors,
)
} }
/// Seals the builder and returns a [`GlobalSettings`] if there are no validation errors, else returns errors. /// Seals the builder and returns a [`GlobalSettings`] if there are no validation errors, else returns errors.
@@ -261,14 +234,7 @@ mod tests {
); );
assert_eq!(global_settings_config.network_spawn_timeout(), 600); assert_eq!(global_settings_config.network_spawn_timeout(), 600);
assert_eq!(global_settings_config.node_spawn_timeout(), 120); assert_eq!(global_settings_config.node_spawn_timeout(), 120);
assert_eq!( assert_eq!(global_settings_config.local_ip().unwrap().to_string().as_str(), "10.0.0.1");
global_settings_config
.local_ip()
.unwrap()
.to_string()
.as_str(),
"10.0.0.1"
);
assert_eq!( assert_eq!(
global_settings_config.base_dir().unwrap(), global_settings_config.base_dir().unwrap(),
Path::new("/home/nonroot/mynetwork") Path::new("/home/nonroot/mynetwork")
@@ -299,14 +265,7 @@ mod tests {
); );
assert_eq!(global_settings_config.network_spawn_timeout(), 600); assert_eq!(global_settings_config.network_spawn_timeout(), 600);
assert_eq!(global_settings_config.node_spawn_timeout(), 600); assert_eq!(global_settings_config.node_spawn_timeout(), 600);
assert_eq!( assert_eq!(global_settings_config.local_ip().unwrap().to_string().as_str(), "10.0.0.1");
global_settings_config
.local_ip()
.unwrap()
.to_string()
.as_str(),
"10.0.0.1"
);
} }
#[test] #[test]
@@ -345,10 +304,7 @@ mod tests {
#[test] #[test]
fn global_settings_builder_should_fails_and_returns_an_error_if_local_ip_is_invalid() { fn global_settings_builder_should_fails_and_returns_an_error_if_local_ip_is_invalid() {
let errors = GlobalSettingsBuilder::new() let errors = GlobalSettingsBuilder::new().with_local_ip("invalid").build().unwrap_err();
.with_local_ip("invalid")
.build()
.unwrap_err();
assert_eq!(errors.len(), 1); assert_eq!(errors.len(), 1);
assert_eq!( assert_eq!(
@@ -63,10 +63,7 @@ impl Default for HrmpChannelConfigBuilder<Initial> {
impl<A> HrmpChannelConfigBuilder<A> { impl<A> HrmpChannelConfigBuilder<A> {
fn transition<B>(&self, config: HrmpChannelConfig) -> HrmpChannelConfigBuilder<B> { fn transition<B>(&self, config: HrmpChannelConfig) -> HrmpChannelConfigBuilder<B> {
HrmpChannelConfigBuilder { HrmpChannelConfigBuilder { config, _state: PhantomData }
config,
_state: PhantomData,
}
} }
} }
@@ -77,38 +74,26 @@ impl HrmpChannelConfigBuilder<Initial> {
/// Set the sending parachain ID. /// Set the sending parachain ID.
pub fn with_sender(self, sender: ParaId) -> HrmpChannelConfigBuilder<WithSender> { pub fn with_sender(self, sender: ParaId) -> HrmpChannelConfigBuilder<WithSender> {
self.transition(HrmpChannelConfig { self.transition(HrmpChannelConfig { sender, ..self.config })
sender,
..self.config
})
} }
} }
impl HrmpChannelConfigBuilder<WithSender> { impl HrmpChannelConfigBuilder<WithSender> {
/// Set the receiving parachain ID. /// Set the receiving parachain ID.
pub fn with_recipient(self, recipient: ParaId) -> HrmpChannelConfigBuilder<WithRecipient> { pub fn with_recipient(self, recipient: ParaId) -> HrmpChannelConfigBuilder<WithRecipient> {
self.transition(HrmpChannelConfig { self.transition(HrmpChannelConfig { recipient, ..self.config })
recipient,
..self.config
})
} }
} }
impl HrmpChannelConfigBuilder<WithRecipient> { impl HrmpChannelConfigBuilder<WithRecipient> {
/// Set the max capacity of messages in the channel. /// Set the max capacity of messages in the channel.
pub fn with_max_capacity(self, max_capacity: u32) -> Self { pub fn with_max_capacity(self, max_capacity: u32) -> Self {
self.transition(HrmpChannelConfig { self.transition(HrmpChannelConfig { max_capacity, ..self.config })
max_capacity,
..self.config
})
} }
/// Set the maximum size of a message in the channel. /// Set the maximum size of a message in the channel.
pub fn with_max_message_size(self, max_message_size: u32) -> Self { pub fn with_max_message_size(self, max_message_size: u32) -> Self {
self.transition(HrmpChannelConfig { self.transition(HrmpChannelConfig { max_message_size, ..self.config })
max_message_size,
..self.config
})
} }
pub fn build(self) -> HrmpChannelConfig { pub fn build(self) -> HrmpChannelConfig {
@@ -47,9 +47,7 @@ impl NetworkConfig {
/// The relay chain of the network. /// The relay chain of the network.
pub fn relaychain(&self) -> &RelaychainConfig { pub fn relaychain(&self) -> &RelaychainConfig {
self.relaychain self.relaychain.as_ref().expect(&format!("{RELAY_NOT_NONE}, {THIS_IS_A_BUG}"))
.as_ref()
.expect(&format!("{RELAY_NOT_NONE}, {THIS_IS_A_BUG}"))
} }
/// The teyrchains of the network. /// The teyrchains of the network.
@@ -123,26 +121,14 @@ impl NetworkConfig {
let relaychain_default_db_snapshot: Option<AssetLocation> = let relaychain_default_db_snapshot: Option<AssetLocation> =
network_config.relaychain().default_db_snapshot().cloned(); network_config.relaychain().default_db_snapshot().cloned();
let default_args: Vec<Arg> = network_config let default_args: Vec<Arg> =
.relaychain() network_config.relaychain().default_args().into_iter().cloned().collect();
.default_args()
.into_iter()
.cloned()
.collect();
let mut nodes: Vec<NodeConfig> = network_config let mut nodes: Vec<NodeConfig> =
.relaychain() network_config.relaychain().nodes().into_iter().cloned().collect();
.nodes()
.into_iter()
.cloned()
.collect();
let group_nodes: Vec<GroupNodeConfig> = network_config let group_nodes: Vec<GroupNodeConfig> =
.relaychain() network_config.relaychain().group_node_configs().into_iter().cloned().collect();
.group_node_configs()
.into_iter()
.cloned()
.collect();
if let Some(group) = group_nodes.iter().find(|n| n.count == 0) { if let Some(group) = group_nodes.iter().find(|n| n.count == 0) {
return Err(anyhow!( return Err(anyhow!(
@@ -203,11 +189,8 @@ impl NetworkConfig {
let default_args: Vec<Arg> = para.default_args().into_iter().cloned().collect(); let default_args: Vec<Arg> = para.default_args().into_iter().cloned().collect();
let group_collators: Vec<GroupNodeConfig> = para let group_collators: Vec<GroupNodeConfig> =
.group_collators_configs() para.group_collators_configs().into_iter().cloned().collect();
.into_iter()
.cloned()
.collect();
if let Some(group) = group_collators.iter().find(|n| n.count == 0) { if let Some(group) = group_collators.iter().find(|n| n.count == 0) {
return Err(anyhow!( return Err(anyhow!(
@@ -287,9 +270,7 @@ fn populate_collator_with_defaults(
} }
if teyrchain_default_db_snapshot.is_some() && collator.db_snapshot.is_none() { if teyrchain_default_db_snapshot.is_some() && collator.db_snapshot.is_none() {
collator collator.db_snapshot.clone_from(teyrchain_default_db_snapshot);
.db_snapshot
.clone_from(teyrchain_default_db_snapshot);
} }
if !default_args.is_empty() && collator.args().is_empty() { if !default_args.is_empty() && collator.args().is_empty() {
@@ -405,12 +386,7 @@ impl<A> NetworkConfigBuilder<A> {
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
errors: Vec<anyhow::Error>, errors: Vec<anyhow::Error>,
) -> NetworkConfigBuilder<B> { ) -> NetworkConfigBuilder<B> {
NetworkConfigBuilder { NetworkConfigBuilder { config, errors, validation_context, _state: PhantomData }
config,
errors,
validation_context,
_state: PhantomData,
}
} }
} }
@@ -453,16 +429,9 @@ impl NetworkConfigBuilder<Initial> {
RelaychainConfigBuilder<relaychain::Initial>, RelaychainConfigBuilder<relaychain::Initial>,
) -> RelaychainConfigBuilder<relaychain::WithAtLeastOneNode>, ) -> RelaychainConfigBuilder<relaychain::WithAtLeastOneNode>,
) -> NetworkConfigBuilder<WithRelaychain> { ) -> NetworkConfigBuilder<WithRelaychain> {
match f(RelaychainConfigBuilder::new( match f(RelaychainConfigBuilder::new(self.validation_context.clone())).build() {
self.validation_context.clone(),
))
.build()
{
Ok(relaychain) => Self::transition( Ok(relaychain) => Self::transition(
NetworkConfig { NetworkConfig { relaychain: Some(relaychain), ..self.config },
relaychain: Some(relaychain),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -479,10 +448,7 @@ impl NetworkConfigBuilder<WithRelaychain> {
) -> Self { ) -> Self {
match f(GlobalSettingsBuilder::new()).build() { match f(GlobalSettingsBuilder::new()).build() {
Ok(global_settings) => Self::transition( Ok(global_settings) => Self::transition(
NetworkConfig { NetworkConfig { global_settings, ..self.config },
global_settings,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -646,10 +612,7 @@ mod tests {
.with_chain("myparachain1") .with_chain("myparachain1")
.with_initial_balance(100_000) .with_initial_balance(100_000)
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator1").with_command("command1").validator(true)
.with_name("collator1")
.with_command("command1")
.validator(true)
}) })
}) })
.with_parachain(|parachain| { .with_parachain(|parachain| {
@@ -658,10 +621,7 @@ mod tests {
.with_chain("myparachain2") .with_chain("myparachain2")
.with_initial_balance(0) .with_initial_balance(0)
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator2").with_command("command2").validator(true)
.with_name("collator2")
.with_command("command2")
.validator(true)
}) })
}) })
.with_hrmp_channel(|hrmp_channel1| { .with_hrmp_channel(|hrmp_channel1| {
@@ -679,9 +639,7 @@ mod tests {
.with_max_message_size(250) .with_max_message_size(250)
}) })
.with_global_settings(|global_settings| { .with_global_settings(|global_settings| {
global_settings global_settings.with_network_spawn_timeout(1200).with_node_spawn_timeout(240)
.with_network_spawn_timeout(1200)
.with_node_spawn_timeout(240)
}) })
.build() .build()
.unwrap(); .unwrap();
@@ -693,13 +651,7 @@ mod tests {
assert_eq!(node.name(), "node"); assert_eq!(node.name(), "node");
assert_eq!(node.command().unwrap().as_str(), "command"); assert_eq!(node.command().unwrap().as_str(), "command");
assert!(node.is_validator()); assert!(node.is_validator());
assert_eq!( assert_eq!(network_config.relaychain().random_nominators_count().unwrap(), 10);
network_config
.relaychain()
.random_nominators_count()
.unwrap(),
10
);
// teyrchains // teyrchains
assert_eq!(network_config.teyrchains().len(), 2); assert_eq!(network_config.teyrchains().len(), 2);
@@ -743,10 +695,7 @@ mod tests {
assert_eq!(hrmp_channel2.max_message_size(), 250); assert_eq!(hrmp_channel2.max_message_size(), 250);
// global settings // global settings
assert_eq!( assert_eq!(network_config.global_settings().network_spawn_timeout(), 1200);
network_config.global_settings().network_spawn_timeout(),
1200
);
assert_eq!(network_config.global_settings().node_spawn_timeout(), 240); assert_eq!(network_config.global_settings().node_spawn_timeout(), 240);
assert!(network_config.global_settings().tear_down_on_failure()); assert!(network_config.global_settings().tear_down_on_failure());
} }
@@ -767,10 +716,7 @@ mod tests {
.with_chain("myparachain") .with_chain("myparachain")
.with_initial_balance(100_000) .with_initial_balance(100_000)
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator1").with_command("command1").validator(true)
.with_name("collator1")
.with_command("command1")
.validator(true)
}) })
}) })
.build() .build()
@@ -839,9 +785,7 @@ mod tests {
.with_chain("myparachain1") .with_chain("myparachain1")
.with_initial_balance(100_000) .with_initial_balance(100_000)
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator1").with_command("invalid command")
.with_name("collator1")
.with_command("invalid command")
}) })
}) })
.with_parachain(|parachain| { .with_parachain(|parachain| {
@@ -850,15 +794,14 @@ mod tests {
.with_chain("myparachain2") .with_chain("myparachain2")
.with_initial_balance(100_000) .with_initial_balance(100_000)
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator2").validator(true).with_resources(
.with_name("collator2") |resources| {
.validator(true)
.with_resources(|resources| {
resources resources
.with_limit_cpu("1000m") .with_limit_cpu("1000m")
.with_request_memory("1Gi") .with_request_memory("1Gi")
.with_request_cpu("invalid") .with_request_cpu("invalid")
}) },
)
}) })
}) })
.build() .build()
@@ -891,10 +834,7 @@ mod tests {
.with_chain("myparachain") .with_chain("myparachain")
.with_initial_balance(100_000) .with_initial_balance(100_000)
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator").with_command("command").validator(true)
.with_name("collator")
.with_command("command")
.validator(true)
}) })
}) })
.with_global_settings(|global_settings| { .with_global_settings(|global_settings| {
@@ -968,10 +908,11 @@ mod tests {
.with_default_args(vec![("-lparachain", "debug").into()]) .with_default_args(vec![("-lparachain", "debug").into()])
.with_validator(|node| node.with_name("alice")) .with_validator(|node| node.with_name("alice"))
.with_validator(|node| { .with_validator(|node| {
node.with_name("bob") node.with_name("bob").invulnerable(false).bootnode(true).with_args(vec![(
.invulnerable(false) "--database",
.bootnode(true) "paritydb-experimental",
.with_args(vec![("--database", "paritydb-experimental").into()]) )
.into()])
}) })
}) })
.build() .build()
@@ -1160,10 +1101,8 @@ mod tests {
#[test] #[test]
fn the_toml_config_with_custom_settings() { fn the_toml_config_with_custom_settings() {
let settings = GlobalSettingsBuilder::new() let settings =
.with_base_dir("/tmp/test-demo") GlobalSettingsBuilder::new().with_base_dir("/tmp/test-demo").build().unwrap();
.build()
.unwrap();
let load_from_toml = NetworkConfig::load_from_toml_with_settings( let load_from_toml = NetworkConfig::load_from_toml_with_settings(
"./testing/snapshots/0000-small-network.toml", "./testing/snapshots/0000-small-network.toml",
@@ -1210,10 +1149,7 @@ mod tests {
// We need to assert parts of the network config separately because the expected one contains the chain default context which // We need to assert parts of the network config separately because the expected one contains the chain default context which
// is used for dumbing to tomp while the // is used for dumbing to tomp while the
// while loaded // while loaded
assert_eq!( assert_eq!(expected.relaychain().chain(), load_from_toml.relaychain().chain());
expected.relaychain().chain(),
load_from_toml.relaychain().chain()
);
assert_eq!( assert_eq!(
expected.relaychain().default_args(), expected.relaychain().default_args(),
load_from_toml.relaychain().default_args() load_from_toml.relaychain().default_args()
@@ -1237,16 +1173,10 @@ mod tests {
assert_eq!(expected_node.name(), loaded_node.name()); assert_eq!(expected_node.name(), loaded_node.name());
assert_eq!(expected_node.command(), loaded_node.command()); assert_eq!(expected_node.command(), loaded_node.command());
assert_eq!(expected_node.args(), loaded_node.args()); assert_eq!(expected_node.args(), loaded_node.args());
assert_eq!( assert_eq!(expected_node.is_invulnerable(), loaded_node.is_invulnerable());
expected_node.is_invulnerable(),
loaded_node.is_invulnerable()
);
assert_eq!(expected_node.is_validator(), loaded_node.is_validator()); assert_eq!(expected_node.is_validator(), loaded_node.is_validator());
assert_eq!(expected_node.is_bootnode(), loaded_node.is_bootnode()); assert_eq!(expected_node.is_bootnode(), loaded_node.is_bootnode());
assert_eq!( assert_eq!(expected_node.initial_balance(), loaded_node.initial_balance());
expected_node.initial_balance(),
loaded_node.initial_balance()
);
}); });
} }
@@ -1392,21 +1322,12 @@ mod tests {
assert_eq!(expected_node.args(), loaded_node.args()); assert_eq!(expected_node.args(), loaded_node.args());
assert_eq!(expected_node.is_validator(), loaded_node.is_validator()); assert_eq!(expected_node.is_validator(), loaded_node.is_validator());
assert_eq!(expected_node.is_bootnode(), loaded_node.is_bootnode()); assert_eq!(expected_node.is_bootnode(), loaded_node.is_bootnode());
assert_eq!( assert_eq!(expected_node.initial_balance(), loaded_node.initial_balance());
expected_node.initial_balance(), assert_eq!(expected_node.is_invulnerable(), loaded_node.is_invulnerable());
loaded_node.initial_balance()
);
assert_eq!(
expected_node.is_invulnerable(),
loaded_node.is_invulnerable()
);
}); });
expected expected.teyrchains().iter().zip(load_from_toml.teyrchains().iter()).for_each(
.teyrchains() |(expected_parachain, loaded_parachain)| {
.iter()
.zip(load_from_toml.teyrchains().iter())
.for_each(|(expected_parachain, loaded_parachain)| {
assert_eq!(expected_parachain.id(), loaded_parachain.id()); assert_eq!(expected_parachain.id(), loaded_parachain.id());
assert_eq!(expected_parachain.chain(), loaded_parachain.chain()); assert_eq!(expected_parachain.chain(), loaded_parachain.chain());
assert_eq!( assert_eq!(
@@ -1429,10 +1350,7 @@ mod tests {
expected_parachain.default_command(), expected_parachain.default_command(),
loaded_parachain.default_command() loaded_parachain.default_command()
); );
assert_eq!( assert_eq!(expected_parachain.default_image(), loaded_parachain.default_image());
expected_parachain.default_image(),
loaded_parachain.default_image()
);
assert_eq!( assert_eq!(
expected_parachain.collators().len(), expected_parachain.collators().len(),
loaded_parachain.collators().len() loaded_parachain.collators().len()
@@ -1449,10 +1367,7 @@ mod tests {
expected_collator.is_validator(), expected_collator.is_validator(),
loaded_collator.is_validator() loaded_collator.is_validator()
); );
assert_eq!( assert_eq!(expected_collator.is_bootnode(), loaded_collator.is_bootnode());
expected_collator.is_bootnode(),
loaded_collator.is_bootnode()
);
assert_eq!( assert_eq!(
expected_collator.is_invulnerable(), expected_collator.is_invulnerable(),
loaded_collator.is_invulnerable() loaded_collator.is_invulnerable()
@@ -1462,18 +1377,13 @@ mod tests {
loaded_collator.initial_balance() loaded_collator.initial_balance()
); );
}); });
}); },
expected
.hrmp_channels()
.iter()
.zip(load_from_toml.hrmp_channels().iter())
.for_each(|(expected_hrmp_channel, loaded_hrmp_channel)| {
assert_eq!(expected_hrmp_channel.sender(), loaded_hrmp_channel.sender());
assert_eq!(
expected_hrmp_channel.recipient(),
loaded_hrmp_channel.recipient()
); );
expected.hrmp_channels().iter().zip(load_from_toml.hrmp_channels().iter()).for_each(
|(expected_hrmp_channel, loaded_hrmp_channel)| {
assert_eq!(expected_hrmp_channel.sender(), loaded_hrmp_channel.sender());
assert_eq!(expected_hrmp_channel.recipient(), loaded_hrmp_channel.recipient());
assert_eq!( assert_eq!(
expected_hrmp_channel.max_capacity(), expected_hrmp_channel.max_capacity(),
loaded_hrmp_channel.max_capacity() loaded_hrmp_channel.max_capacity()
@@ -1482,7 +1392,8 @@ mod tests {
expected_hrmp_channel.max_message_size(), expected_hrmp_channel.max_message_size(),
loaded_hrmp_channel.max_message_size() loaded_hrmp_channel.max_message_size()
); );
}); },
);
} }
#[test] #[test]
@@ -1558,11 +1469,8 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
expected expected.teyrchains().iter().zip(load_from_toml.teyrchains().iter()).for_each(
.teyrchains() |(expected_parachain, loaded_parachain)| {
.iter()
.zip(load_from_toml.teyrchains().iter())
.for_each(|(expected_parachain, loaded_parachain)| {
assert_eq!(expected_parachain.id(), loaded_parachain.id()); assert_eq!(expected_parachain.id(), loaded_parachain.id());
assert_eq!(expected_parachain.chain(), loaded_parachain.chain()); assert_eq!(expected_parachain.chain(), loaded_parachain.chain());
assert_eq!( assert_eq!(
@@ -1585,10 +1493,7 @@ mod tests {
expected_parachain.default_command(), expected_parachain.default_command(),
loaded_parachain.default_command() loaded_parachain.default_command()
); );
assert_eq!( assert_eq!(expected_parachain.default_image(), loaded_parachain.default_image());
expected_parachain.default_image(),
loaded_parachain.default_image()
);
assert_eq!( assert_eq!(
expected_parachain.collators().len(), expected_parachain.collators().len(),
loaded_parachain.collators().len() loaded_parachain.collators().len()
@@ -1605,10 +1510,7 @@ mod tests {
expected_collator.is_validator(), expected_collator.is_validator(),
loaded_collator.is_validator() loaded_collator.is_validator()
); );
assert_eq!( assert_eq!(expected_collator.is_bootnode(), loaded_collator.is_bootnode());
expected_collator.is_bootnode(),
loaded_collator.is_bootnode()
);
assert_eq!( assert_eq!(
expected_collator.is_invulnerable(), expected_collator.is_invulnerable(),
loaded_collator.is_invulnerable() loaded_collator.is_invulnerable()
@@ -1618,7 +1520,8 @@ mod tests {
loaded_collator.initial_balance() loaded_collator.initial_balance()
); );
}); });
}); },
);
} }
#[test] #[test]
@@ -1649,17 +1552,13 @@ mod tests {
.build() .build()
.unwrap_err(); .unwrap_err();
assert_eq!( assert_eq!(errors.first().unwrap().to_string(), "relaychain.chain: can't be empty");
errors.first().unwrap().to_string(),
"relaychain.chain: can't be empty"
);
} }
#[test] #[test]
fn with_chain_and_nodes_should_fail_with_empty_node_list() { fn with_chain_and_nodes_should_fail_with_empty_node_list() {
let errors = NetworkConfigBuilder::with_chain_and_nodes("rococo-local", vec![]) let errors =
.build() NetworkConfigBuilder::with_chain_and_nodes("rococo-local", vec![]).build().unwrap_err();
.unwrap_err();
assert_eq!( assert_eq!(
errors.first().unwrap().to_string(), errors.first().unwrap().to_string(),
@@ -1726,10 +1625,7 @@ mod tests {
.build() .build()
.unwrap_err(); .unwrap_err();
assert_eq!( assert_eq!(errors.first().unwrap().to_string(), "teyrchain[1].can't be empty");
errors.first().unwrap().to_string(),
"teyrchain[1].can't be empty"
);
} }
#[test] #[test]
@@ -1789,10 +1685,7 @@ mod tests {
.with_fullnode(|node| node.with_name("node").with_command("command")) .with_fullnode(|node| node.with_name("node").with_command("command"))
}) })
.with_parachain(|parachain| { .with_parachain(|parachain| {
parachain parachain.with_id(1).with_chain("myparachain1").with_collator(|collator| {
.with_id(1)
.with_chain("myparachain1")
.with_collator(|collator| {
collator.with_name("collator1").with_command("command1") collator.with_name("collator1").with_command("command1")
}) })
}) })
@@ -1821,10 +1714,7 @@ mod tests {
.with_fullnode(|node| node.with_name("node").with_command("command")) .with_fullnode(|node| node.with_name("node").with_command("command"))
}) })
.with_parachain(|parachain| { .with_parachain(|parachain| {
parachain parachain.with_id(1).with_chain("myparachain1").with_collator(|collator| {
.with_id(1)
.with_chain("myparachain1")
.with_collator(|collator| {
collator.with_name("collator1").with_command("command1") collator.with_name("collator1").with_command("command1")
}) })
}) })
@@ -1854,10 +1744,7 @@ mod tests {
NetworkConfig::load_from_toml("./testing/snapshots/0006-without-rc-chain-name.toml") NetworkConfig::load_from_toml("./testing/snapshots/0006-without-rc-chain-name.toml")
.unwrap(); .unwrap();
assert_eq!( assert_eq!("rococo-local", loaded_from_toml.relaychain().chain().as_str());
"rococo-local",
loaded_from_toml.relaychain().chain().as_str()
);
} }
#[test] #[test]
@@ -1868,12 +1755,7 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
loaded_from_toml loaded_from_toml.relaychain().nodes().iter().filter(|n| n.name() == "alice").count(),
.relaychain()
.nodes()
.iter()
.filter(|n| n.name() == "alice")
.count(),
1 1
); );
assert_eq!( assert_eq!(
@@ -178,9 +178,7 @@ impl Default for RelaychainConfigBuilder<Initial> {
fn default() -> Self { fn default() -> Self {
Self { Self {
config: RelaychainConfig { config: RelaychainConfig {
chain: "default" chain: "default".try_into().expect(&format!("{DEFAULT_TYPESTATE} {THIS_IS_A_BUG}")),
.try_into()
.expect(&format!("{DEFAULT_TYPESTATE} {THIS_IS_A_BUG}")),
default_command: None, default_command: None,
default_image: None, default_image: None,
default_resources: None, default_resources: None,
@@ -213,12 +211,7 @@ impl<A> RelaychainConfigBuilder<A> {
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
errors: Vec<anyhow::Error>, errors: Vec<anyhow::Error>,
) -> RelaychainConfigBuilder<B> { ) -> RelaychainConfigBuilder<B> {
RelaychainConfigBuilder { RelaychainConfigBuilder { config, validation_context, errors, _state: PhantomData }
config,
validation_context,
errors,
_state: PhantomData,
}
} }
fn default_chain_context(&self) -> ChainDefaultContext { fn default_chain_context(&self) -> ChainDefaultContext {
@@ -235,10 +228,7 @@ impl<A> RelaychainConfigBuilder<A> {
where where
F: FnOnce(NodeConfigBuilder<node::Initial>) -> NodeConfigBuilder<node::Buildable>, F: FnOnce(NodeConfigBuilder<node::Initial>) -> NodeConfigBuilder<node::Buildable>,
{ {
f(NodeConfigBuilder::new( f(NodeConfigBuilder::new(self.default_chain_context(), self.validation_context.clone()))
self.default_chain_context(),
self.validation_context.clone(),
))
} }
} }
@@ -246,10 +236,7 @@ impl RelaychainConfigBuilder<Initial> {
pub fn new( pub fn new(
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
) -> RelaychainConfigBuilder<Initial> { ) -> RelaychainConfigBuilder<Initial> {
Self { Self { validation_context, ..Self::default() }
validation_context,
..Self::default()
}
} }
/// Set the chain name (e.g. rococo-local). /// Set the chain name (e.g. rococo-local).
@@ -260,10 +247,7 @@ impl RelaychainConfigBuilder<Initial> {
{ {
match chain.try_into() { match chain.try_into() {
Ok(chain) => Self::transition( Ok(chain) => Self::transition(
RelaychainConfig { RelaychainConfig { chain, ..self.config },
chain,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -285,10 +269,7 @@ impl RelaychainConfigBuilder<WithChain> {
{ {
match command.try_into() { match command.try_into() {
Ok(command) => Self::transition( Ok(command) => Self::transition(
RelaychainConfig { RelaychainConfig { default_command: Some(command), ..self.config },
default_command: Some(command),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -308,10 +289,7 @@ impl RelaychainConfigBuilder<WithChain> {
{ {
match image.try_into() { match image.try_into() {
Ok(image) => Self::transition( Ok(image) => Self::transition(
RelaychainConfig { RelaychainConfig { default_image: Some(image), ..self.config },
default_image: Some(image),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -330,10 +308,7 @@ impl RelaychainConfigBuilder<WithChain> {
) -> Self { ) -> Self {
match f(ResourcesBuilder::new()).build() { match f(ResourcesBuilder::new()).build() {
Ok(default_resources) => Self::transition( Ok(default_resources) => Self::transition(
RelaychainConfig { RelaychainConfig { default_resources: Some(default_resources), ..self.config },
default_resources: Some(default_resources),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -354,10 +329,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the default database snapshot location that will be used for state. Can be overridden. /// Set the default database snapshot location that will be used for state. Can be overridden.
pub fn with_default_db_snapshot(self, location: impl Into<AssetLocation>) -> Self { pub fn with_default_db_snapshot(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { default_db_snapshot: Some(location.into()), ..self.config },
default_db_snapshot: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -366,10 +338,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the default arguments that will be used to execute the node command. Can be overridden. /// Set the default arguments that will be used to execute the node command. Can be overridden.
pub fn with_default_args(self, args: Vec<Arg>) -> Self { pub fn with_default_args(self, args: Vec<Arg>) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { default_args: args, ..self.config },
default_args: args,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -378,10 +347,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the location of a pre-existing chain specification for the relay chain. /// Set the location of a pre-existing chain specification for the relay chain.
pub fn with_chain_spec_path(self, location: impl Into<AssetLocation>) -> Self { pub fn with_chain_spec_path(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { chain_spec_path: Some(location.into()), ..self.config },
chain_spec_path: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -390,10 +356,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the location of a wasm to override the chain-spec. /// Set the location of a wasm to override the chain-spec.
pub fn with_wasm_override(self, location: impl Into<AssetLocation>) -> Self { pub fn with_wasm_override(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { wasm_override: Some(location.into()), ..self.config },
wasm_override: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -402,10 +365,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the chain-spec command _template_ for the relay chain. /// Set the chain-spec command _template_ for the relay chain.
pub fn with_chain_spec_command(self, cmd_template: impl Into<String>) -> Self { pub fn with_chain_spec_command(self, cmd_template: impl Into<String>) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { chain_spec_command: Some(cmd_template.into()), ..self.config },
chain_spec_command: Some(cmd_template.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -425,10 +385,7 @@ impl RelaychainConfigBuilder<WithChain> {
ChainSpecRuntime::new(location.into()) ChainSpecRuntime::new(location.into())
}; };
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { chain_spec_runtime: Some(chain_spec_runtime), ..self.config },
chain_spec_runtime: Some(chain_spec_runtime),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -437,10 +394,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set if the chain-spec command needs to be run locally or not (false by default) /// Set if the chain-spec command needs to be run locally or not (false by default)
pub fn chain_spec_command_is_local(self, choice: bool) -> Self { pub fn chain_spec_command_is_local(self, choice: bool) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { chain_spec_command_is_local: choice, ..self.config },
chain_spec_command_is_local: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -473,10 +427,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the maximum number of nominations to create per nominator. /// Set the maximum number of nominations to create per nominator.
pub fn with_max_nominations(self, max_nominations: u8) -> Self { pub fn with_max_nominations(self, max_nominations: u8) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { max_nominations: Some(max_nominations), ..self.config },
max_nominations: Some(max_nominations),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -502,10 +453,7 @@ impl RelaychainConfigBuilder<WithChain> {
) -> RelaychainConfigBuilder<WithAtLeastOneNode> { ) -> RelaychainConfigBuilder<WithAtLeastOneNode> {
match self.create_node_builder(f).validator(true).build() { match self.create_node_builder(f).validator(true).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
RelaychainConfig { RelaychainConfig { nodes: [self.config.nodes, vec![node]].concat(), ..self.config },
nodes: [self.config.nodes, vec![node]].concat(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -531,10 +479,7 @@ impl RelaychainConfigBuilder<WithChain> {
) -> RelaychainConfigBuilder<WithAtLeastOneNode> { ) -> RelaychainConfigBuilder<WithAtLeastOneNode> {
match self.create_node_builder(f).validator(false).build() { match self.create_node_builder(f).validator(false).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
RelaychainConfig { RelaychainConfig { nodes: [self.config.nodes, vec![node]].concat(), ..self.config },
nodes: [self.config.nodes, vec![node]].concat(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -565,10 +510,7 @@ impl RelaychainConfigBuilder<WithChain> {
) -> RelaychainConfigBuilder<WithAtLeastOneNode> { ) -> RelaychainConfigBuilder<WithAtLeastOneNode> {
match self.create_node_builder(f).build() { match self.create_node_builder(f).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
RelaychainConfig { RelaychainConfig { nodes: vec![node], ..self.config },
nodes: vec![node],
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -598,10 +540,7 @@ impl RelaychainConfigBuilder<WithChain> {
.build() .build()
{ {
Ok(group_node) => Self::transition( Ok(group_node) => Self::transition(
RelaychainConfig { RelaychainConfig { node_groups: vec![group_node], ..self.config },
node_groups: vec![group_node],
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -622,10 +561,7 @@ impl RelaychainConfigBuilder<WithChain> {
/// Set the location or inline value of a json to override the raw chain-spec. /// Set the location or inline value of a json to override the raw chain-spec.
pub fn with_raw_spec_override(self, overrides: impl Into<JsonOverrides>) -> Self { pub fn with_raw_spec_override(self, overrides: impl Into<JsonOverrides>) -> Self {
Self::transition( Self::transition(
RelaychainConfig { RelaychainConfig { raw_spec_override: Some(overrides.into()), ..self.config },
raw_spec_override: Some(overrides.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -641,10 +577,7 @@ impl RelaychainConfigBuilder<WithAtLeastOneNode> {
) -> RelaychainConfigBuilder<WithAtLeastOneNode> { ) -> RelaychainConfigBuilder<WithAtLeastOneNode> {
match self.create_node_builder(f).validator(true).build() { match self.create_node_builder(f).validator(true).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
RelaychainConfig { RelaychainConfig { nodes: [self.config.nodes, vec![node]].concat(), ..self.config },
nodes: [self.config.nodes, vec![node]].concat(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -670,10 +603,7 @@ impl RelaychainConfigBuilder<WithAtLeastOneNode> {
) -> Self { ) -> Self {
match self.create_node_builder(f).validator(false).build() { match self.create_node_builder(f).validator(false).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
RelaychainConfig { RelaychainConfig { nodes: [self.config.nodes, vec![node]].concat(), ..self.config },
nodes: [self.config.nodes, vec![node]].concat(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -704,10 +634,7 @@ impl RelaychainConfigBuilder<WithAtLeastOneNode> {
) -> Self { ) -> Self {
match self.create_node_builder(f).build() { match self.create_node_builder(f).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
RelaychainConfig { RelaychainConfig { nodes: [self.config.nodes, vec![node]].concat(), ..self.config },
nodes: [self.config.nodes, vec![node]].concat(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -783,10 +710,7 @@ mod tests {
.with_default_image("myrepo:myimage") .with_default_image("myrepo:myimage")
.with_default_command("default_command") .with_default_command("default_command")
.with_default_resources(|resources| { .with_default_resources(|resources| {
resources resources.with_limit_cpu("500M").with_limit_memory("1G").with_request_cpu("250M")
.with_limit_cpu("500M")
.with_limit_memory("1G")
.with_request_cpu("250M")
}) })
.with_default_db_snapshot("https://www.urltomysnapshot.com/file.tgz") .with_default_db_snapshot("https://www.urltomysnapshot.com/file.tgz")
.with_chain_spec_path("./path/to/chain/spec.json") .with_chain_spec_path("./path/to/chain/spec.json")
@@ -811,14 +735,8 @@ mod tests {
assert_eq!(node2.name(), "node2"); assert_eq!(node2.name(), "node2");
assert_eq!(node2.command().unwrap().as_str(), "command2"); assert_eq!(node2.command().unwrap().as_str(), "command2");
assert!(node2.is_validator()); assert!(node2.is_validator());
assert_eq!( assert_eq!(relaychain_config.default_command().unwrap().as_str(), "default_command");
relaychain_config.default_command().unwrap().as_str(), assert_eq!(relaychain_config.default_image().unwrap().as_str(), "myrepo:myimage");
"default_command"
);
assert_eq!(
relaychain_config.default_image().unwrap().as_str(),
"myrepo:myimage"
);
let default_resources = relaychain_config.default_resources().unwrap(); let default_resources = relaychain_config.default_resources().unwrap();
assert_eq!(default_resources.limit_cpu().unwrap().as_str(), "500M"); assert_eq!(default_resources.limit_cpu().unwrap().as_str(), "500M");
assert_eq!(default_resources.limit_memory().unwrap().as_str(), "1G"); assert_eq!(default_resources.limit_memory().unwrap().as_str(), "1G");
@@ -836,11 +754,7 @@ mod tests {
AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/runtime.wasm" AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/runtime.wasm"
)); ));
assert_eq!( assert_eq!(
relaychain_config relaychain_config.chain_spec_runtime().unwrap().preset.as_deref(),
.chain_spec_runtime()
.unwrap()
.preset
.as_deref(),
Some("local_testnet") Some("local_testnet")
); );
assert!(matches!( assert!(matches!(
@@ -848,10 +762,7 @@ mod tests {
AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/override/runtime.wasm" AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/override/runtime.wasm"
)); ));
let args: Vec<Arg> = vec![("--arg1", "value1").into(), "--option2".into()]; let args: Vec<Arg> = vec![("--arg1", "value1").into(), "--option2".into()];
assert_eq!( assert_eq!(relaychain_config.default_args(), args.iter().collect::<Vec<_>>());
relaychain_config.default_args(),
args.iter().collect::<Vec<_>>()
);
assert_eq!(relaychain_config.random_nominators_count().unwrap(), 42); assert_eq!(relaychain_config.random_nominators_count().unwrap(), 42);
assert_eq!(relaychain_config.max_nominations().unwrap(), 5); assert_eq!(relaychain_config.max_nominations().unwrap(), 5);
@@ -914,9 +825,7 @@ mod tests {
let errors = RelaychainConfigBuilder::new(Default::default()) let errors = RelaychainConfigBuilder::new(Default::default())
.with_chain("chain") .with_chain("chain")
.with_default_resources(|default_resources| { .with_default_resources(|default_resources| {
default_resources default_resources.with_limit_memory("100m").with_request_cpu("invalid")
.with_limit_memory("100m")
.with_request_cpu("invalid")
}) })
.with_validator(|node| node.with_name("node").with_command("command")) .with_validator(|node| node.with_name("node").with_command("command"))
.build() .build()
@@ -1040,14 +949,7 @@ mod tests {
assert_eq!(relaychain_config.chain().as_str(), "chain"); assert_eq!(relaychain_config.chain().as_str(), "chain");
assert_eq!(relaychain_config.nodes().len(), 1); assert_eq!(relaychain_config.nodes().len(), 1);
assert_eq!(relaychain_config.group_node_configs().len(), 1); assert_eq!(relaychain_config.group_node_configs().len(), 1);
assert_eq!( assert_eq!(relaychain_config.group_node_configs().first().unwrap().count, 2);
relaychain_config
.group_node_configs()
.first()
.unwrap()
.count,
2
);
let &node = relaychain_config.nodes().first().unwrap(); let &node = relaychain_config.nodes().first().unwrap();
assert_eq!(node.name(), "node"); assert_eq!(node.name(), "node");
assert_eq!(node.command().unwrap().as_str(), "node_command"); assert_eq!(node.command().unwrap().as_str(), "node_command");
@@ -1055,14 +957,8 @@ mod tests {
let group_nodes = relaychain_config.group_node_configs(); let group_nodes = relaychain_config.group_node_configs();
let group_base_node = group_nodes.first().unwrap(); let group_base_node = group_nodes.first().unwrap();
assert_eq!(group_base_node.base_config.name(), "group_node"); assert_eq!(group_base_node.base_config.name(), "group_node");
assert_eq!( assert_eq!(group_base_node.base_config.command().unwrap().as_str(), "some_command");
group_base_node.base_config.command().unwrap().as_str(), assert_eq!(group_base_node.base_config.image().unwrap().as_str(), "repo:image");
"some_command"
);
assert_eq!(
group_base_node.base_config.image().unwrap().as_str(),
"repo:image"
);
assert!(group_base_node.base_config.is_validator()); assert!(group_base_node.base_config.is_validator());
} }
@@ -37,9 +37,8 @@ pub fn generate_unique_node_name(
node_name: impl Into<String>, node_name: impl Into<String>,
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
) -> String { ) -> String {
let mut context = validation_context let mut context =
.try_borrow_mut() validation_context.try_borrow_mut().expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
.expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
generate_unique_node_name_from_names(node_name, &mut context.used_nodes_names) generate_unique_node_name_from_names(node_name, &mut context.used_nodes_names)
} }
@@ -87,9 +86,8 @@ pub fn ensure_port_unique(
port: Port, port: Port,
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
let mut context = validation_context let mut context =
.try_borrow_mut() validation_context.try_borrow_mut().expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
.expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
if !context.used_ports.contains(&port) { if !context.used_ports.contains(&port) {
context.used_ports.push(port); context.used_ports.push(port);
@@ -103,9 +101,8 @@ pub fn generate_unique_para_id(
para_id: ParaId, para_id: ParaId,
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
) -> String { ) -> String {
let mut context = validation_context let mut context =
.try_borrow_mut() validation_context.try_borrow_mut().expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
.expect(&format!("{BORROWABLE}, {THIS_IS_A_BUG}"));
if let Some(suffix) = context.used_para_ids.get_mut(&para_id) { if let Some(suffix) = context.used_para_ids.get_mut(&para_id) {
*suffix += 1; *suffix += 1;
@@ -55,10 +55,7 @@ pub struct EnvVar {
impl From<(&str, &str)> for EnvVar { impl From<(&str, &str)> for EnvVar {
fn from((name, value): (&str, &str)) -> Self { fn from((name, value): (&str, &str)) -> Self {
Self { Self { name: name.to_owned(), value: value.to_owned() }
name: name.to_owned(),
value: value.to_owned(),
}
} }
} }
@@ -415,12 +412,7 @@ impl<A> NodeConfigBuilder<A> {
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
errors: Vec<anyhow::Error>, errors: Vec<anyhow::Error>,
) -> NodeConfigBuilder<B> { ) -> NodeConfigBuilder<B> {
NodeConfigBuilder { NodeConfigBuilder { config, validation_context, errors, _state: PhantomData }
config,
validation_context,
errors,
_state: PhantomData,
}
} }
} }
@@ -450,10 +442,7 @@ impl NodeConfigBuilder<Initial> {
match ensure_value_is_not_empty(&name) { match ensure_value_is_not_empty(&name) {
Ok(_) => Self::transition( Ok(_) => Self::transition(
NodeConfig { NodeConfig { name, ..self.config },
name,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -479,10 +468,7 @@ impl NodeConfigBuilder<Buildable> {
{ {
match command.try_into() { match command.try_into() {
Ok(command) => Self::transition( Ok(command) => Self::transition(
NodeConfig { NodeConfig { command: Some(command), ..self.config },
command: Some(command),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -502,10 +488,7 @@ impl NodeConfigBuilder<Buildable> {
{ {
match subcommand.try_into() { match subcommand.try_into() {
Ok(subcommand) => Self::transition( Ok(subcommand) => Self::transition(
NodeConfig { NodeConfig { subcommand: Some(subcommand), ..self.config },
subcommand: Some(subcommand),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -525,10 +508,7 @@ impl NodeConfigBuilder<Buildable> {
{ {
match image.try_into() { match image.try_into() {
Ok(image) => Self::transition( Ok(image) => Self::transition(
NodeConfig { NodeConfig { image: Some(image), ..self.config },
image: Some(image),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -542,23 +522,13 @@ impl NodeConfigBuilder<Buildable> {
/// Set the arguments that will be used when launching the node. Override the default. /// Set the arguments that will be used when launching the node. Override the default.
pub fn with_args(self, args: Vec<Arg>) -> Self { pub fn with_args(self, args: Vec<Arg>) -> Self {
Self::transition( Self::transition(NodeConfig { args, ..self.config }, self.validation_context, self.errors)
NodeConfig {
args,
..self.config
},
self.validation_context,
self.errors,
)
} }
/// Set whether the node is a validator. /// Set whether the node is a validator.
pub fn validator(self, choice: bool) -> Self { pub fn validator(self, choice: bool) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { is_validator: choice, ..self.config },
is_validator: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -567,10 +537,7 @@ impl NodeConfigBuilder<Buildable> {
/// Set whether the node is invulnerable. /// Set whether the node is invulnerable.
pub fn invulnerable(self, choice: bool) -> Self { pub fn invulnerable(self, choice: bool) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { is_invulnerable: choice, ..self.config },
is_invulnerable: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -579,10 +546,7 @@ impl NodeConfigBuilder<Buildable> {
/// Set whether the node is a bootnode. /// Set whether the node is a bootnode.
pub fn bootnode(self, choice: bool) -> Self { pub fn bootnode(self, choice: bool) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { is_bootnode: choice, ..self.config },
is_bootnode: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -591,10 +555,7 @@ impl NodeConfigBuilder<Buildable> {
/// Override the EVM session key to use for the node /// Override the EVM session key to use for the node
pub fn with_override_eth_key(self, session_key: impl Into<String>) -> Self { pub fn with_override_eth_key(self, session_key: impl Into<String>) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { override_eth_key: Some(session_key.into()), ..self.config },
override_eth_key: Some(session_key.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -603,10 +564,7 @@ impl NodeConfigBuilder<Buildable> {
/// Set the node initial balance. /// Set the node initial balance.
pub fn with_initial_balance(self, initial_balance: u128) -> Self { pub fn with_initial_balance(self, initial_balance: u128) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { initial_balance: initial_balance.into(), ..self.config },
initial_balance: initial_balance.into(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -616,11 +574,7 @@ impl NodeConfigBuilder<Buildable> {
pub fn with_env(self, env: Vec<impl Into<EnvVar>>) -> Self { pub fn with_env(self, env: Vec<impl Into<EnvVar>>) -> Self {
let env = env.into_iter().map(|var| var.into()).collect::<Vec<_>>(); let env = env.into_iter().map(|var| var.into()).collect::<Vec<_>>();
Self::transition( Self::transition(NodeConfig { env, ..self.config }, self.validation_context, self.errors)
NodeConfig { env, ..self.config },
self.validation_context,
self.errors,
)
} }
/// Set the bootnodes addresses that the node will try to connect to. Override the default. /// Set the bootnodes addresses that the node will try to connect to. Override the default.
@@ -645,10 +599,7 @@ impl NodeConfigBuilder<Buildable> {
} }
Self::transition( Self::transition(
NodeConfig { NodeConfig { bootnodes_addresses: addrs, ..self.config },
bootnodes_addresses: addrs,
..self.config
},
self.validation_context, self.validation_context,
merge_errors_vecs(self.errors, errors), merge_errors_vecs(self.errors, errors),
) )
@@ -658,10 +609,7 @@ impl NodeConfigBuilder<Buildable> {
pub fn with_resources(self, f: impl FnOnce(ResourcesBuilder) -> ResourcesBuilder) -> Self { pub fn with_resources(self, f: impl FnOnce(ResourcesBuilder) -> ResourcesBuilder) -> Self {
match f(ResourcesBuilder::new()).build() { match f(ResourcesBuilder::new()).build() {
Ok(resources) => Self::transition( Ok(resources) => Self::transition(
NodeConfig { NodeConfig { resources: Some(resources), ..self.config },
resources: Some(resources),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -683,10 +631,7 @@ impl NodeConfigBuilder<Buildable> {
pub fn with_ws_port(self, ws_port: Port) -> Self { pub fn with_ws_port(self, ws_port: Port) -> Self {
match ensure_port_unique(ws_port, self.validation_context.clone()) { match ensure_port_unique(ws_port, self.validation_context.clone()) {
Ok(_) => Self::transition( Ok(_) => Self::transition(
NodeConfig { NodeConfig { ws_port: Some(ws_port), ..self.config },
ws_port: Some(ws_port),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -702,10 +647,7 @@ impl NodeConfigBuilder<Buildable> {
pub fn with_rpc_port(self, rpc_port: Port) -> Self { pub fn with_rpc_port(self, rpc_port: Port) -> Self {
match ensure_port_unique(rpc_port, self.validation_context.clone()) { match ensure_port_unique(rpc_port, self.validation_context.clone()) {
Ok(_) => Self::transition( Ok(_) => Self::transition(
NodeConfig { NodeConfig { rpc_port: Some(rpc_port), ..self.config },
rpc_port: Some(rpc_port),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -721,10 +663,7 @@ impl NodeConfigBuilder<Buildable> {
pub fn with_prometheus_port(self, prometheus_port: Port) -> Self { pub fn with_prometheus_port(self, prometheus_port: Port) -> Self {
match ensure_port_unique(prometheus_port, self.validation_context.clone()) { match ensure_port_unique(prometheus_port, self.validation_context.clone()) {
Ok(_) => Self::transition( Ok(_) => Self::transition(
NodeConfig { NodeConfig { prometheus_port: Some(prometheus_port), ..self.config },
prometheus_port: Some(prometheus_port),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -740,10 +679,7 @@ impl NodeConfigBuilder<Buildable> {
pub fn with_p2p_port(self, p2p_port: Port) -> Self { pub fn with_p2p_port(self, p2p_port: Port) -> Self {
match ensure_port_unique(p2p_port, self.validation_context.clone()) { match ensure_port_unique(p2p_port, self.validation_context.clone()) {
Ok(_) => Self::transition( Ok(_) => Self::transition(
NodeConfig { NodeConfig { p2p_port: Some(p2p_port), ..self.config },
p2p_port: Some(p2p_port),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -759,10 +695,7 @@ impl NodeConfigBuilder<Buildable> {
/// if and only if the multiaddress is set to use `webrtc`. /// if and only if the multiaddress is set to use `webrtc`.
pub fn with_p2p_cert_hash(self, p2p_cert_hash: impl Into<String>) -> Self { pub fn with_p2p_cert_hash(self, p2p_cert_hash: impl Into<String>) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { p2p_cert_hash: Some(p2p_cert_hash.into()), ..self.config },
p2p_cert_hash: Some(p2p_cert_hash.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -771,10 +704,7 @@ impl NodeConfigBuilder<Buildable> {
/// Set the database snapshot that will be used to launch the node. Override the default. /// Set the database snapshot that will be used to launch the node. Override the default.
pub fn with_db_snapshot(self, location: impl Into<AssetLocation>) -> Self { pub fn with_db_snapshot(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { db_snapshot: Some(location.into()), ..self.config },
db_snapshot: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -783,10 +713,7 @@ impl NodeConfigBuilder<Buildable> {
/// Set the node log path that will be used to launch the node. /// Set the node log path that will be used to launch the node.
pub fn with_log_path(self, log_path: impl Into<PathBuf>) -> Self { pub fn with_log_path(self, log_path: impl Into<PathBuf>) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { node_log_path: Some(log_path.into()), ..self.config },
node_log_path: Some(log_path.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -795,10 +722,7 @@ impl NodeConfigBuilder<Buildable> {
/// Set the keystore path override. /// Set the keystore path override.
pub fn with_keystore_path(self, keystore_path: impl Into<PathBuf>) -> Self { pub fn with_keystore_path(self, keystore_path: impl Into<PathBuf>) -> Self {
Self::transition( Self::transition(
NodeConfig { NodeConfig { keystore_path: Some(keystore_path.into()), ..self.config },
keystore_path: Some(keystore_path.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -869,13 +793,7 @@ impl GroupNodeConfigBuilder<Initial> {
Err((_name, errors)) => (errors, NodeConfig::default()), Err((_name, errors)) => (errors, NodeConfig::default()),
}; };
Self { Self { base_config, count: 1, validation_context, errors, _state: PhantomData }
base_config,
count: 1,
validation_context,
errors,
_state: PhantomData,
}
} }
/// Set the base node config using a closure. /// Set the base node config using a closure.
@@ -932,10 +850,7 @@ impl GroupNodeConfigBuilder<Buildable> {
return Err((self.base_config.name().to_string(), self.errors)); return Err((self.base_config.name().to_string(), self.errors));
} }
Ok(GroupNodeConfig { Ok(GroupNodeConfig { base_config: self.base_config, count: self.count })
base_config: self.base_config,
count: self.count,
})
} }
} }
@@ -1031,10 +946,8 @@ mod tests {
fn node_config_builder_should_use_unique_name_if_node_name_already_used() { fn node_config_builder_should_use_unique_name_if_node_name_already_used() {
let mut used_nodes_names = HashSet::new(); let mut used_nodes_names = HashSet::new();
used_nodes_names.insert("mynode".into()); used_nodes_names.insert("mynode".into());
let validation_context = Rc::new(RefCell::new(ValidationContext { let validation_context =
used_nodes_names, Rc::new(RefCell::new(ValidationContext { used_nodes_names, ..Default::default() }));
..Default::default()
}));
let node_config = let node_config =
NodeConfigBuilder::new(ChainDefaultContext::default(), validation_context) NodeConfigBuilder::new(ChainDefaultContext::default(), validation_context)
.with_name("mynode") .with_name("mynode")
@@ -1143,9 +1056,7 @@ mod tests {
NodeConfigBuilder::new(ChainDefaultContext::default(), Default::default()) NodeConfigBuilder::new(ChainDefaultContext::default(), Default::default())
.with_name("node") .with_name("node")
.with_resources(|resources| { .with_resources(|resources| {
resources resources.with_limit_cpu("invalid").with_request_memory("invalid")
.with_limit_cpu("invalid")
.with_request_memory("invalid")
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1171,9 +1082,7 @@ mod tests {
.with_command("invalid command") .with_command("invalid command")
.with_image("myinvalid.image") .with_image("myinvalid.image")
.with_resources(|resources| { .with_resources(|resources| {
resources resources.with_limit_cpu("invalid").with_request_memory("invalid")
.with_limit_cpu("invalid")
.with_request_memory("invalid")
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1288,9 +1197,7 @@ mod tests {
#[test] #[test]
fn node_config_builder_should_fails_if_node_name_is_empty() { fn node_config_builder_should_fails_if_node_name_is_empty() {
let validation_context = Rc::new(RefCell::new(ValidationContext { let validation_context = Rc::new(RefCell::new(ValidationContext { ..Default::default() }));
..Default::default()
}));
let (_, errors) = let (_, errors) =
NodeConfigBuilder::new(ChainDefaultContext::default(), validation_context) NodeConfigBuilder::new(ChainDefaultContext::default(), validation_context)
@@ -1340,14 +1247,8 @@ mod tests {
assert_eq!(group_config.count, 5); assert_eq!(group_config.count, 5);
assert_eq!(group_config.base_config.name(), "node"); assert_eq!(group_config.base_config.name(), "node");
assert_eq!( assert_eq!(group_config.base_config.command().unwrap().as_str(), "some_command");
group_config.base_config.command().unwrap().as_str(), assert_eq!(group_config.base_config.image().unwrap().as_str(), "repo:image");
"some_command"
);
assert_eq!(
group_config.base_config.image().unwrap().as_str(),
"repo:image"
);
assert!(group_config.base_config.is_validator()); assert!(group_config.base_config.is_validator());
assert!(group_config.base_config.is_invulnerable()); assert!(group_config.base_config.is_invulnerable());
assert!(group_config.base_config.is_bootnode()); assert!(group_config.base_config.is_bootnode());
@@ -105,10 +105,7 @@ impl Serialize for Resources {
if self.limit_memory.is_some() || self.limit_memory.is_some() { if self.limit_memory.is_some() || self.limit_memory.is_some() {
state.serialize_field( state.serialize_field(
"limits", "limits",
&ResourcesField { &ResourcesField { memory: self.limit_memory.clone(), cpu: self.limit_cpu.clone() },
memory: self.limit_memory.clone(),
cpu: self.limit_cpu.clone(),
},
)?; )?;
} else { } else {
state.skip_field("limits")?; state.skip_field("limits")?;
@@ -210,10 +207,7 @@ impl ResourcesBuilder {
{ {
match quantity.try_into() { match quantity.try_into() {
Ok(quantity) => Self::transition( Ok(quantity) => Self::transition(
Resources { Resources { request_memory: Some(quantity), ..self.config },
request_memory: Some(quantity),
..self.config
},
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
@@ -231,10 +225,7 @@ impl ResourcesBuilder {
{ {
match quantity.try_into() { match quantity.try_into() {
Ok(quantity) => Self::transition( Ok(quantity) => Self::transition(
Resources { Resources { request_cpu: Some(quantity), ..self.config },
request_cpu: Some(quantity),
..self.config
},
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
@@ -252,10 +243,7 @@ impl ResourcesBuilder {
{ {
match quantity.try_into() { match quantity.try_into() {
Ok(quantity) => Self::transition( Ok(quantity) => Self::transition(
Resources { Resources { limit_memory: Some(quantity), ..self.config },
limit_memory: Some(quantity),
..self.config
},
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
@@ -273,10 +261,7 @@ impl ResourcesBuilder {
{ {
match quantity.try_into() { match quantity.try_into() {
Ok(quantity) => Self::transition( Ok(quantity) => Self::transition(
Resources { Resources { limit_cpu: Some(quantity), ..self.config },
limit_cpu: Some(quantity),
..self.config
},
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
@@ -304,10 +289,7 @@ mod tests {
macro_rules! impl_resources_quantity_unit_test { macro_rules! impl_resources_quantity_unit_test {
($val:literal) => {{ ($val:literal) => {{
let resources = ResourcesBuilder::new() let resources = ResourcesBuilder::new().with_request_memory($val).build().unwrap();
.with_request_memory($val)
.build()
.unwrap();
assert_eq!(resources.request_memory().unwrap().as_str(), $val); assert_eq!(resources.request_memory().unwrap().as_str(), $val);
assert_eq!(resources.request_cpu(), None); assert_eq!(resources.request_cpu(), None);
@@ -470,9 +452,8 @@ mod tests {
#[test] #[test]
fn resources_config_builder_should_fails_and_returns_multiple_error_if_couldnt_parse_multiple_fields( fn resources_config_builder_should_fails_and_returns_multiple_error_if_couldnt_parse_multiple_fields(
) { ) {
let resources_builder = ResourcesBuilder::new() let resources_builder =
.with_limit_cpu("invalid") ResourcesBuilder::new().with_limit_cpu("invalid").with_request_memory("invalid");
.with_request_memory("invalid");
let errors = resources_builder.build().err().unwrap(); let errors = resources_builder.build().err().unwrap();
@@ -430,10 +430,7 @@ where
T: AsRef<str> + Clone, T: AsRef<str> + Clone,
{ {
fn from((option, values): (&str, &[T])) -> Self { fn from((option, values): (&str, &[T])) -> Self {
Self::Array( Self::Array(option.to_owned(), values.iter().map(|v| v.as_ref().to_string()).collect())
option.to_owned(),
values.iter().map(|v| v.as_ref().to_string()).collect(),
)
} }
} }
@@ -442,10 +439,7 @@ where
T: AsRef<str>, T: AsRef<str>,
{ {
fn from((option, values): (&str, Vec<T>)) -> Self { fn from((option, values): (&str, Vec<T>)) -> Self {
Self::Array( Self::Array(option.to_owned(), values.into_iter().map(|v| v.as_ref().to_string()).collect())
option.to_owned(),
values.into_iter().map(|v| v.as_ref().to_string()).collect(),
)
} }
} }
@@ -559,17 +553,11 @@ pub struct ChainSpecRuntime {
impl ChainSpecRuntime { impl ChainSpecRuntime {
pub fn new(location: AssetLocation) -> Self { pub fn new(location: AssetLocation) -> Self {
ChainSpecRuntime { ChainSpecRuntime { location, preset: None }
location,
preset: None,
}
} }
pub fn with_preset(location: AssetLocation, preset: impl Into<String>) -> Self { pub fn with_preset(location: AssetLocation, preset: impl Into<String>) -> Self {
ChainSpecRuntime { ChainSpecRuntime { location, preset: Some(preset.into()) }
location,
preset: Some(preset.into()),
}
} }
} }
@@ -825,24 +813,15 @@ mod tests {
fn converting_a_str_with_whitespaces_into_a_chain_should_fails() { fn converting_a_str_with_whitespaces_into_a_chain_should_fails() {
let got: Result<Chain, ConversionError> = "my chain".try_into(); let got: Result<Chain, ConversionError> = "my chain".try_into();
assert!(matches!( assert!(matches!(got.clone().unwrap_err(), ConversionError::ContainsWhitespaces(_)));
got.clone().unwrap_err(), assert_eq!(got.unwrap_err().to_string(), "'my chain' shouldn't contains whitespace");
ConversionError::ContainsWhitespaces(_)
));
assert_eq!(
got.unwrap_err().to_string(),
"'my chain' shouldn't contains whitespace"
);
} }
#[test] #[test]
fn converting_an_empty_str_into_a_chain_should_fails() { fn converting_an_empty_str_into_a_chain_should_fails() {
let got: Result<Chain, ConversionError> = "".try_into(); let got: Result<Chain, ConversionError> = "".try_into();
assert!(matches!( assert!(matches!(got.clone().unwrap_err(), ConversionError::CantBeEmpty));
got.clone().unwrap_err(),
ConversionError::CantBeEmpty
));
assert_eq!(got.unwrap_err().to_string(), "can't be empty"); assert_eq!(got.unwrap_err().to_string(), "can't be empty");
} }
@@ -897,34 +876,19 @@ mod tests {
fn converting_a_str_with_whitespaces_into_a_command_should_fails() { fn converting_a_str_with_whitespaces_into_a_command_should_fails() {
let got: Result<Command, ConversionError> = "my command".try_into(); let got: Result<Command, ConversionError> = "my command".try_into();
assert!(matches!( assert!(matches!(got.clone().unwrap_err(), ConversionError::ContainsWhitespaces(_)));
got.clone().unwrap_err(), assert_eq!(got.unwrap_err().to_string(), "'my command' shouldn't contains whitespace");
ConversionError::ContainsWhitespaces(_)
));
assert_eq!(
got.unwrap_err().to_string(),
"'my command' shouldn't contains whitespace"
);
} }
#[test] #[test]
fn test_convert_to_json_overrides() { fn test_convert_to_json_overrides() {
let url: AssetLocation = "https://example.com/overrides.json".into(); let url: AssetLocation = "https://example.com/overrides.json".into();
assert!(matches!( assert!(matches!(url.into(), JsonOverrides::Location(AssetLocation::Url(_))));
url.into(),
JsonOverrides::Location(AssetLocation::Url(_))
));
let path: AssetLocation = "/path/to/overrides.json".into(); let path: AssetLocation = "/path/to/overrides.json".into();
assert!(matches!( assert!(matches!(path.into(), JsonOverrides::Location(AssetLocation::FilePath(_))));
path.into(),
JsonOverrides::Location(AssetLocation::FilePath(_))
));
let inline = serde_json::json!({ "para_id": 2000}); let inline = serde_json::json!({ "para_id": 2000});
assert!(matches!( assert!(matches!(inline.into(), JsonOverrides::Json(serde_json::Value::Object(_))));
inline.into(),
JsonOverrides::Json(serde_json::Value::Object(_))
));
} }
} }
@@ -114,10 +114,7 @@ pub struct TeyrchainConfig {
chain: Option<Chain>, chain: Option<Chain>,
#[serde(flatten)] #[serde(flatten)]
registration_strategy: Option<RegistrationStrategy>, registration_strategy: Option<RegistrationStrategy>,
#[serde( #[serde(skip_serializing_if = "super::utils::is_true", default = "default_as_true")]
skip_serializing_if = "super::utils::is_true",
default = "default_as_true"
)]
onboard_as_teyrchain: bool, onboard_as_teyrchain: bool,
#[serde(rename = "balance", default = "default_initial_balance")] #[serde(rename = "balance", default = "default_initial_balance")]
initial_balance: U128, initial_balance: U128,
@@ -432,10 +429,7 @@ impl<A, C> TeyrchainConfigBuilder<A, C> {
where where
F: FnOnce(NodeConfigBuilder<node::Initial>) -> NodeConfigBuilder<node::Buildable>, F: FnOnce(NodeConfigBuilder<node::Initial>) -> NodeConfigBuilder<node::Buildable>,
{ {
f(NodeConfigBuilder::new( f(NodeConfigBuilder::new(self.default_chain_context(), self.validation_context.clone()))
self.default_chain_context(),
self.validation_context.clone(),
))
} }
} }
@@ -444,10 +438,7 @@ impl TeyrchainConfigBuilder<Initial, Bootstrap> {
pub fn new( pub fn new(
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
) -> TeyrchainConfigBuilder<Initial, Bootstrap> { ) -> TeyrchainConfigBuilder<Initial, Bootstrap> {
Self { Self { validation_context, ..Self::default() }
validation_context,
..Self::default()
}
} }
} }
@@ -456,10 +447,7 @@ impl TeyrchainConfigBuilder<WithId, Bootstrap> {
/// using an extrinsic or in genesis. /// using an extrinsic or in genesis.
pub fn with_registration_strategy(self, strategy: RegistrationStrategy) -> Self { pub fn with_registration_strategy(self, strategy: RegistrationStrategy) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { registration_strategy: Some(strategy), ..self.config },
registration_strategy: Some(strategy),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -484,10 +472,7 @@ impl TeyrchainConfigBuilder<WithId, Running> {
), ),
RegistrationStrategy::Manual | RegistrationStrategy::UsingExtrinsic => { RegistrationStrategy::Manual | RegistrationStrategy::UsingExtrinsic => {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { registration_strategy: Some(strategy), ..self.config },
registration_strategy: Some(strategy),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -501,10 +486,7 @@ impl TeyrchainConfigBuilder<Initial, Running> {
pub fn new_with_running( pub fn new_with_running(
validation_context: Rc<RefCell<ValidationContext>>, validation_context: Rc<RefCell<ValidationContext>>,
) -> TeyrchainConfigBuilder<Initial, Running> { ) -> TeyrchainConfigBuilder<Initial, Running> {
let mut builder = Self { let mut builder = Self { validation_context, ..Self::default() };
validation_context,
..Self::default()
};
// override the registration strategy // override the registration strategy
builder.config.registration_strategy = Some(RegistrationStrategy::UsingExtrinsic); builder.config.registration_strategy = Some(RegistrationStrategy::UsingExtrinsic);
@@ -517,11 +499,7 @@ impl<C: Context> TeyrchainConfigBuilder<Initial, C> {
pub fn with_id(self, id: u32) -> TeyrchainConfigBuilder<WithId, C> { pub fn with_id(self, id: u32) -> TeyrchainConfigBuilder<WithId, C> {
let unique_id = generate_unique_para_id(id, self.validation_context.clone()); let unique_id = generate_unique_para_id(id, self.validation_context.clone());
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { id, unique_id, ..self.config },
id,
unique_id,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -538,10 +516,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
{ {
match chain.try_into() { match chain.try_into() {
Ok(chain) => Self::transition( Ok(chain) => Self::transition(
TeyrchainConfig { TeyrchainConfig { chain: Some(chain), ..self.config },
chain: Some(chain),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -556,10 +531,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set whether the teyrchain should be onboarded or stay a parathread. Default is ```true```. /// Set whether the teyrchain should be onboarded or stay a parathread. Default is ```true```.
pub fn onboard_as_teyrchain(self, choice: bool) -> Self { pub fn onboard_as_teyrchain(self, choice: bool) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { onboard_as_teyrchain: choice, ..self.config },
onboard_as_teyrchain: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -573,10 +545,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the initial balance of the teyrchain account. /// Set the initial balance of the teyrchain account.
pub fn with_initial_balance(self, initial_balance: u128) -> Self { pub fn with_initial_balance(self, initial_balance: u128) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { initial_balance: initial_balance.into(), ..self.config },
initial_balance: initial_balance.into(),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -590,10 +559,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
{ {
match command.try_into() { match command.try_into() {
Ok(command) => Self::transition( Ok(command) => Self::transition(
TeyrchainConfig { TeyrchainConfig { default_command: Some(command), ..self.config },
default_command: Some(command),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -613,10 +579,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
{ {
match image.try_into() { match image.try_into() {
Ok(image) => Self::transition( Ok(image) => Self::transition(
TeyrchainConfig { TeyrchainConfig { default_image: Some(image), ..self.config },
default_image: Some(image),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -635,10 +598,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
) -> Self { ) -> Self {
match f(ResourcesBuilder::new()).build() { match f(ResourcesBuilder::new()).build() {
Ok(default_resources) => Self::transition( Ok(default_resources) => Self::transition(
TeyrchainConfig { TeyrchainConfig { default_resources: Some(default_resources), ..self.config },
default_resources: Some(default_resources),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -659,10 +619,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the default database snapshot location that will be used for state. Can be overridden. /// Set the default database snapshot location that will be used for state. Can be overridden.
pub fn with_default_db_snapshot(self, location: impl Into<AssetLocation>) -> Self { pub fn with_default_db_snapshot(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { default_db_snapshot: Some(location.into()), ..self.config },
default_db_snapshot: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -671,10 +628,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the default arguments that will be used to execute the collator command. Can be overridden. /// Set the default arguments that will be used to execute the collator command. Can be overridden.
pub fn with_default_args(self, args: Vec<Arg>) -> Self { pub fn with_default_args(self, args: Vec<Arg>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { default_args: args, ..self.config },
default_args: args,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -683,10 +637,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the location of a pre-existing genesis WASM runtime blob of the teyrchain. /// Set the location of a pre-existing genesis WASM runtime blob of the teyrchain.
pub fn with_genesis_wasm_path(self, location: impl Into<AssetLocation>) -> Self { pub fn with_genesis_wasm_path(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { genesis_wasm_path: Some(location.into()), ..self.config },
genesis_wasm_path: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -700,20 +651,14 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
{ {
match command.try_into() { match command.try_into() {
Ok(command) => Self::transition( Ok(command) => Self::transition(
TeyrchainConfig { TeyrchainConfig { genesis_wasm_generator: Some(command), ..self.config },
genesis_wasm_generator: Some(command),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
self.config, self.config,
self.validation_context, self.validation_context,
merge_errors( merge_errors(self.errors, FieldError::GenesisWasmGenerator(error.into()).into()),
self.errors,
FieldError::GenesisWasmGenerator(error.into()).into(),
),
), ),
} }
} }
@@ -721,10 +666,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the location of a pre-existing genesis state of the teyrchain. /// Set the location of a pre-existing genesis state of the teyrchain.
pub fn with_genesis_state_path(self, location: impl Into<AssetLocation>) -> Self { pub fn with_genesis_state_path(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { genesis_state_path: Some(location.into()), ..self.config },
genesis_state_path: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -738,20 +680,14 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
{ {
match command.try_into() { match command.try_into() {
Ok(command) => Self::transition( Ok(command) => Self::transition(
TeyrchainConfig { TeyrchainConfig { genesis_state_generator: Some(command), ..self.config },
genesis_state_generator: Some(command),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
Err(error) => Self::transition( Err(error) => Self::transition(
self.config, self.config,
self.validation_context, self.validation_context,
merge_errors( merge_errors(self.errors, FieldError::GenesisStateGenerator(error.into()).into()),
self.errors,
FieldError::GenesisStateGenerator(error.into()).into(),
),
), ),
} }
} }
@@ -759,10 +695,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the genesis overrides as a JSON object. /// Set the genesis overrides as a JSON object.
pub fn with_genesis_overrides(self, genesis_overrides: impl Into<serde_json::Value>) -> Self { pub fn with_genesis_overrides(self, genesis_overrides: impl Into<serde_json::Value>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { genesis_overrides: Some(genesis_overrides.into()), ..self.config },
genesis_overrides: Some(genesis_overrides.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -771,10 +704,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the location of a pre-existing chain specification for the teyrchain. /// Set the location of a pre-existing chain specification for the teyrchain.
pub fn with_chain_spec_path(self, location: impl Into<AssetLocation>) -> Self { pub fn with_chain_spec_path(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { chain_spec_path: Some(location.into()), ..self.config },
chain_spec_path: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -783,10 +713,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the chain-spec command _template_ for the relay chain. /// Set the chain-spec command _template_ for the relay chain.
pub fn with_chain_spec_command(self, cmd_template: impl Into<String>) -> Self { pub fn with_chain_spec_command(self, cmd_template: impl Into<String>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { chain_spec_command: Some(cmd_template.into()), ..self.config },
chain_spec_command: Some(cmd_template.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -806,10 +733,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
ChainSpecRuntime::new(location.into()) ChainSpecRuntime::new(location.into())
}; };
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { chain_spec_runtime: Some(chain_spec_runtime), ..self.config },
chain_spec_runtime: Some(chain_spec_runtime),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -818,10 +742,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the location of a wasm to override the chain-spec. /// Set the location of a wasm to override the chain-spec.
pub fn with_wasm_override(self, location: impl Into<AssetLocation>) -> Self { pub fn with_wasm_override(self, location: impl Into<AssetLocation>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { wasm_override: Some(location.into()), ..self.config },
wasm_override: Some(location.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -830,10 +751,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set if the chain-spec command needs to be run locally or not (false by default) /// Set if the chain-spec command needs to be run locally or not (false by default)
pub fn chain_spec_command_is_local(self, choice: bool) -> Self { pub fn chain_spec_command_is_local(self, choice: bool) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { chain_spec_command_is_local: choice, ..self.config },
chain_spec_command_is_local: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -854,10 +772,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set whether the teyrchain is based on cumulus (true in a majority of case, except adder or undying collators). /// Set whether the teyrchain is based on cumulus (true in a majority of case, except adder or undying collators).
pub fn cumulus_based(self, choice: bool) -> Self { pub fn cumulus_based(self, choice: bool) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { is_cumulus_based: choice, ..self.config },
is_cumulus_based: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -871,10 +786,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set whether the teyrchain is evm based (e.g frontier /evm template) /// Set whether the teyrchain is evm based (e.g frontier /evm template)
pub fn evm_based(self, choice: bool) -> Self { pub fn evm_based(self, choice: bool) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { is_evm_based: choice, ..self.config },
is_evm_based: choice,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -902,10 +814,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
} }
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { bootnodes_addresses: addrs, ..self.config },
bootnodes_addresses: addrs,
..self.config
},
self.validation_context, self.validation_context,
merge_errors_vecs(self.errors, errors), merge_errors_vecs(self.errors, errors),
) )
@@ -914,10 +823,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Do not assign a bootnode role automatically if no nodes are marked as bootnodes. /// Do not assign a bootnode role automatically if no nodes are marked as bootnodes.
pub fn without_default_bootnodes(self) -> Self { pub fn without_default_bootnodes(self) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { no_default_bootnodes: true, ..self.config },
no_default_bootnodes: true,
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -930,10 +836,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
) -> TeyrchainConfigBuilder<WithAtLeastOneCollator, C> { ) -> TeyrchainConfigBuilder<WithAtLeastOneCollator, C> {
match self.create_node_builder(f).validator(true).build() { match self.create_node_builder(f).validator(true).build() {
Ok(collator) => Self::transition( Ok(collator) => Self::transition(
TeyrchainConfig { TeyrchainConfig { collators: vec![collator], ..self.config },
collators: vec![collator],
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -959,10 +862,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
) -> TeyrchainConfigBuilder<WithAtLeastOneCollator, C> { ) -> TeyrchainConfigBuilder<WithAtLeastOneCollator, C> {
match self.create_node_builder(f).validator(false).build() { match self.create_node_builder(f).validator(false).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
TeyrchainConfig { TeyrchainConfig { collators: vec![node], ..self.config },
collators: vec![node],
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -993,10 +893,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
) -> TeyrchainConfigBuilder<WithAtLeastOneCollator, C> { ) -> TeyrchainConfigBuilder<WithAtLeastOneCollator, C> {
match self.create_node_builder(f).build() { match self.create_node_builder(f).build() {
Ok(node) => Self::transition( Ok(node) => Self::transition(
TeyrchainConfig { TeyrchainConfig { collators: vec![node], ..self.config },
collators: vec![node],
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
), ),
@@ -1050,10 +947,7 @@ impl<C: Context> TeyrchainConfigBuilder<WithId, C> {
/// Set the location or inline value of json to override the raw chain-spec. /// Set the location or inline value of json to override the raw chain-spec.
pub fn with_raw_spec_override(self, overrides: impl Into<JsonOverrides>) -> Self { pub fn with_raw_spec_override(self, overrides: impl Into<JsonOverrides>) -> Self {
Self::transition( Self::transition(
TeyrchainConfig { TeyrchainConfig { raw_spec_override: Some(overrides.into()), ..self.config },
raw_spec_override: Some(overrides.into()),
..self.config
},
self.validation_context, self.validation_context,
self.errors, self.errors,
) )
@@ -1215,10 +1109,7 @@ mod tests {
.with_default_image("myrepo:myimage") .with_default_image("myrepo:myimage")
.with_default_command("default_command") .with_default_command("default_command")
.with_default_resources(|resources| { .with_default_resources(|resources| {
resources resources.with_limit_cpu("500M").with_limit_memory("1G").with_request_cpu("250M")
.with_limit_cpu("500M")
.with_limit_memory("1G")
.with_request_cpu("250M")
}) })
.with_default_db_snapshot("https://www.urltomysnapshot.com/file.tgz") .with_default_db_snapshot("https://www.urltomysnapshot.com/file.tgz")
.with_default_args(vec![("--arg1", "value1").into(), "--option2".into()]) .with_default_args(vec![("--arg1", "value1").into(), "--option2".into()])
@@ -1240,16 +1131,10 @@ mod tests {
]) ])
.without_default_bootnodes() .without_default_bootnodes()
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator1").with_command("command1").bootnode(true)
.with_name("collator1")
.with_command("command1")
.bootnode(true)
}) })
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator2").with_command("command2").validator(true)
.with_name("collator2")
.with_command("command2")
.validator(true)
}) })
.build() .build()
.unwrap(); .unwrap();
@@ -1272,14 +1157,8 @@ mod tests {
); );
assert!(!teyrchain_config.onboard_as_teyrchain()); assert!(!teyrchain_config.onboard_as_teyrchain());
assert_eq!(teyrchain_config.initial_balance(), 100_000_042); assert_eq!(teyrchain_config.initial_balance(), 100_000_042);
assert_eq!( assert_eq!(teyrchain_config.default_command().unwrap().as_str(), "default_command");
teyrchain_config.default_command().unwrap().as_str(), assert_eq!(teyrchain_config.default_image().unwrap().as_str(), "myrepo:myimage");
"default_command"
);
assert_eq!(
teyrchain_config.default_image().unwrap().as_str(),
"myrepo:myimage"
);
let default_resources = teyrchain_config.default_resources().unwrap(); let default_resources = teyrchain_config.default_resources().unwrap();
assert_eq!(default_resources.limit_cpu().unwrap().as_str(), "500M"); assert_eq!(default_resources.limit_cpu().unwrap().as_str(), "500M");
assert_eq!(default_resources.limit_memory().unwrap().as_str(), "1G"); assert_eq!(default_resources.limit_memory().unwrap().as_str(), "1G");
@@ -1300,38 +1179,21 @@ mod tests {
&teyrchain_config.chain_spec_runtime().unwrap().location, &teyrchain_config.chain_spec_runtime().unwrap().location,
AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/runtime.wasm" AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/runtime.wasm"
)); ));
assert_eq!( assert_eq!(teyrchain_config.chain_spec_runtime().unwrap().preset.as_deref(), Some("dev"));
teyrchain_config
.chain_spec_runtime()
.unwrap()
.preset
.as_deref(),
Some("dev")
);
let args: Vec<Arg> = vec![("--arg1", "value1").into(), "--option2".into()]; let args: Vec<Arg> = vec![("--arg1", "value1").into(), "--option2".into()];
assert_eq!( assert_eq!(teyrchain_config.default_args(), args.iter().collect::<Vec<_>>());
teyrchain_config.default_args(),
args.iter().collect::<Vec<_>>()
);
assert!(matches!( assert!(matches!(
teyrchain_config.genesis_wasm_path().unwrap(), teyrchain_config.genesis_wasm_path().unwrap(),
AssetLocation::Url(value) if value.as_str() == "https://www.backupsite.com/my/wasm/file.tgz" AssetLocation::Url(value) if value.as_str() == "https://www.backupsite.com/my/wasm/file.tgz"
)); ));
assert_eq!( assert_eq!(teyrchain_config.genesis_wasm_generator().unwrap().as_str(), "generator_wasm");
teyrchain_config.genesis_wasm_generator().unwrap().as_str(),
"generator_wasm"
);
assert!(matches!( assert!(matches!(
teyrchain_config.genesis_state_path().unwrap(), teyrchain_config.genesis_state_path().unwrap(),
AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/genesis/state" AssetLocation::FilePath(value) if value.to_str().unwrap() == "./path/to/genesis/state"
)); ));
assert_eq!( assert_eq!(
teyrchain_config teyrchain_config.genesis_state_generator().unwrap().cmd().as_str(),
.genesis_state_generator()
.unwrap()
.cmd()
.as_str(),
"undying-collator" "undying-collator"
); );
@@ -1372,40 +1234,23 @@ mod tests {
.with_chain("myteyrchain") .with_chain("myteyrchain")
.with_genesis_state_generator("generator_state --simple-flag --flag=value") .with_genesis_state_generator("generator_state --simple-flag --flag=value")
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator").with_command("command").validator(true)
.with_name("collator")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
teyrchain_config teyrchain_config.genesis_state_generator().unwrap().cmd().as_str(),
.genesis_state_generator()
.unwrap()
.cmd()
.as_str(),
"generator_state" "generator_state"
); );
assert_eq!( assert_eq!(teyrchain_config.genesis_state_generator().unwrap().args().len(), 2);
teyrchain_config
.genesis_state_generator()
.unwrap()
.args()
.len(),
2
);
let args = teyrchain_config.genesis_state_generator().unwrap().args(); let args = teyrchain_config.genesis_state_generator().unwrap().args();
assert_eq!( assert_eq!(
args, args,
&vec![ &vec![Arg::Flag("--simple-flag".into()), Arg::Option("--flag".into(), "value".into())]
Arg::Flag("--simple-flag".into()),
Arg::Option("--flag".into(), "value".into())
]
); );
} }
@@ -1415,10 +1260,7 @@ mod tests {
.with_id(1000) .with_id(1000)
.with_chain("invalid chain") .with_chain("invalid chain")
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator").with_command("command").validator(true)
.with_name("collator")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1437,10 +1279,7 @@ mod tests {
.with_chain("chain") .with_chain("chain")
.with_default_command("invalid command") .with_default_command("invalid command")
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("node").with_command("command").validator(true)
.with_name("node")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1459,10 +1298,7 @@ mod tests {
.with_chain("chain") .with_chain("chain")
.with_default_image("invalid image") .with_default_image("invalid image")
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("node").with_command("command").validator(true)
.with_name("node")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1481,15 +1317,10 @@ mod tests {
.with_id(1000) .with_id(1000)
.with_chain("chain") .with_chain("chain")
.with_default_resources(|default_resources| { .with_default_resources(|default_resources| {
default_resources default_resources.with_limit_memory("100m").with_request_cpu("invalid")
.with_limit_memory("100m")
.with_request_cpu("invalid")
}) })
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("node").with_command("command").validator(true)
.with_name("node")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1509,10 +1340,7 @@ mod tests {
.with_chain("myteyrchain") .with_chain("myteyrchain")
.with_genesis_wasm_generator("invalid command") .with_genesis_wasm_generator("invalid command")
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator").with_command("command").validator(true)
.with_name("collator")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1532,10 +1360,7 @@ mod tests {
.with_chain("myteyrchain") .with_chain("myteyrchain")
.with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421", "//10.42.153.10/tcp/43111"]) .with_raw_bootnodes_addresses(vec!["/ip4//tcp/45421", "//10.42.153.10/tcp/43111"])
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator").with_command("command").validator(true)
.with_name("collator")
.with_command("command")
.validator(true)
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1557,9 +1382,7 @@ mod tests {
.with_id(1000) .with_id(1000)
.with_chain("myteyrchain") .with_chain("myteyrchain")
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator").with_command("invalid command")
.with_name("collator")
.with_command("invalid command")
}) })
.build() .build()
.unwrap_err(); .unwrap_err();
@@ -1614,9 +1437,7 @@ mod tests {
.invulnerable(true) .invulnerable(true)
.bootnode(true) .bootnode(true)
.with_resources(|resources| { .with_resources(|resources| {
resources resources.with_limit_cpu("invalid").with_request_memory("1G")
.with_limit_cpu("invalid")
.with_request_memory("1G")
}) })
}) })
.with_collator(|collator| { .with_collator(|collator| {
@@ -1732,10 +1553,7 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
assert_eq!( assert_eq!(config.registration_strategy(), Some(&RegistrationStrategy::UsingExtrinsic));
config.registration_strategy(),
Some(&RegistrationStrategy::UsingExtrinsic)
);
} }
#[test] #[test]
@@ -1785,23 +1603,16 @@ mod tests {
.with_default_command("default_command") .with_default_command("default_command")
.without_default_bootnodes() .without_default_bootnodes()
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator1").with_command("command1").bootnode(true)
.with_name("collator1")
.with_command("command1")
.bootnode(true)
}) })
.with_collator_group(|group| { .with_collator_group(|group| {
group.with_count(2).with_base_node(|base| { group.with_count(2).with_base_node(|base| {
base.with_name("collator_group1") base.with_name("collator_group1").with_command("group_command1").bootnode(true)
.with_command("group_command1")
.bootnode(true)
}) })
}) })
.with_collator_group(|group| { .with_collator_group(|group| {
group.with_count(3).with_base_node(|base| { group.with_count(3).with_base_node(|base| {
base.with_name("collator_group2") base.with_name("collator_group2").with_command("group_command2").bootnode(false)
.with_command("group_command2")
.bootnode(false)
}) })
}) })
.build() .build()
@@ -1838,23 +1649,16 @@ mod tests {
.with_default_command("default_command") .with_default_command("default_command")
.without_default_bootnodes() .without_default_bootnodes()
.with_collator(|collator| { .with_collator(|collator| {
collator collator.with_name("collator1").with_command("command1").bootnode(true)
.with_name("collator1")
.with_command("command1")
.bootnode(true)
}) })
.with_collator_group(|group| { .with_collator_group(|group| {
group.with_count(2).with_base_node(|base| { group.with_count(2).with_base_node(|base| {
base.with_name("collator_group1") base.with_name("collator_group1").with_command("group_command1").bootnode(true)
.with_command("group_command1")
.bootnode(true)
}) })
}) })
.with_collator_group(|group| { .with_collator_group(|group| {
group.with_count(0).with_base_node(|base| { group.with_count(0).with_base_node(|base| {
base.with_name("collator_group2") base.with_name("collator_group2").with_command("group_command2").bootnode(false)
.with_command("group_command2")
.bootnode(false)
}) })
}) })
.build(); .build();
@@ -57,12 +57,8 @@ mod tests {
fn generate_for_alice_with_listen_addr() { fn generate_for_alice_with_listen_addr() {
// Should override the ip/port // Should override the ip/port
let peer_id = "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"; // from alice as seed let peer_id = "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"; // from alice as seed
let args: Vec<String> = [ let args: Vec<String> =
"--some", ["--some", "other", "--listen-addr", "/ip4/192.168.100.1/tcp/30333/ws"]
"other",
"--listen-addr",
"/ip4/192.168.100.1/tcp/30333/ws",
]
.iter() .iter()
.map(|x| x.to_string()) .map(|x| x.to_string())
.collect(); .collect();
@@ -78,31 +74,20 @@ mod tests {
fn generate_for_alice_with_listen_addr_without_value_must_fail() { fn generate_for_alice_with_listen_addr_without_value_must_fail() {
// Should override the ip/port // Should override the ip/port
let peer_id = "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"; // from alice as seed let peer_id = "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"; // from alice as seed
let args: Vec<String> = ["--some", "other", "--listen-addr"] let args: Vec<String> =
.iter() ["--some", "other", "--listen-addr"].iter().map(|x| x.to_string()).collect();
.map(|x| x.to_string())
.collect();
let bootnode_addr = generate(peer_id, &LOCALHOST, 5678, args.iter().as_ref(), &None); let bootnode_addr = generate(peer_id, &LOCALHOST, 5678, args.iter().as_ref(), &None);
assert!(bootnode_addr.is_err()); assert!(bootnode_addr.is_err());
assert!(matches!( assert!(matches!(bootnode_addr, Err(GeneratorError::BootnodeAddrGeneration(_))));
bootnode_addr,
Err(GeneratorError::BootnodeAddrGeneration(_))
));
} }
#[test] #[test]
fn generate_for_alice_withcert() { fn generate_for_alice_withcert() {
let peer_id = "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"; // from alice as seed let peer_id = "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"; // from alice as seed
let args: Vec<&str> = vec![]; let args: Vec<&str> = vec![];
let bootnode_addr = generate( let bootnode_addr =
peer_id, generate(peer_id, &LOCALHOST, 5678, &args, &Some(String::from("data"))).unwrap();
&LOCALHOST,
5678,
&args,
&Some(String::from("data")),
)
.unwrap();
assert_eq!( assert_eq!(
&bootnode_addr, &bootnode_addr,
"/ip4/127.0.0.1/tcp/5678/ws/p2p/12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm/certhash/data" "/ip4/127.0.0.1/tcp/5678/ws/p2p/12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm/certhash/data"
@@ -8,12 +8,12 @@ use configuration::{
types::{AssetLocation, Chain, ChainSpecRuntime, JsonOverrides, ParaId}, types::{AssetLocation, Chain, ChainSpecRuntime, JsonOverrides, ParaId},
HrmpChannelConfig, HrmpChannelConfig,
}; };
use pezsc_chain_spec::{GenericChainSpec, GenesisConfigBuilderRuntimeCaller};
use provider::{ use provider::{
constants::NODE_CONFIG_DIR, constants::NODE_CONFIG_DIR,
types::{GenerateFileCommand, GenerateFilesOptions, TransferedFile}, types::{GenerateFileCommand, GenerateFilesOptions, TransferedFile},
DynNamespace, ProviderError, DynNamespace, ProviderError,
}; };
use pezsc_chain_spec::{GenericChainSpec, GenesisConfigBuilderRuntimeCaller};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use support::{constants::THIS_IS_A_BUG, fs::FileSystem, replacer::apply_replacements}; use support::{constants::THIS_IS_A_BUG, fs::FileSystem, replacer::apply_replacements};
@@ -199,27 +199,17 @@ impl ChainSpec {
// if asset_location is some, then copy the asset to the `base_dir` of the ns with the name `<name>-plain.json` // if asset_location is some, then copy the asset to the `base_dir` of the ns with the name `<name>-plain.json`
if let Some(location) = self.asset_location.as_ref() { if let Some(location) = self.asset_location.as_ref() {
let maybe_plain_spec_full_path = scoped_fs.full_path(maybe_plain_spec_path.as_path()); let maybe_plain_spec_full_path = scoped_fs.full_path(maybe_plain_spec_path.as_path());
location location.dump_asset(maybe_plain_spec_full_path).await.map_err(|e| {
.dump_asset(maybe_plain_spec_full_path)
.await
.map_err(|e| {
GeneratorError::ChainSpecGeneration(format!( GeneratorError::ChainSpecGeneration(format!(
"Error {e} dumping location {location:?}" "Error {e} dumping location {location:?}"
)) ))
})?; })?;
} else if let Some(runtime) = self.runtime.as_ref() { } else if let Some(runtime) = self.runtime.as_ref() {
trace!( trace!("Creating chain-spec with runtime from localtion: {}", runtime.location);
"Creating chain-spec with runtime from localtion: {}",
runtime.location
);
// First dump the runtime into the ns scoped fs, since we want to easily reproduce // First dump the runtime into the ns scoped fs, since we want to easily reproduce
let runtime_file_name = PathBuf::from(format!("{}-runtime.wasm", self.chain_spec_name)); let runtime_file_name = PathBuf::from(format!("{}-runtime.wasm", self.chain_spec_name));
let runtime_path_ns = scoped_fs.full_path(runtime_file_name.as_path()); let runtime_path_ns = scoped_fs.full_path(runtime_file_name.as_path());
runtime runtime.location.dump_asset(runtime_path_ns).await.map_err(|e| {
.location
.dump_asset(runtime_path_ns)
.await
.map_err(|e| {
GeneratorError::ChainSpecGeneration(format!( GeneratorError::ChainSpecGeneration(format!(
"Error {e} dumping location {:?}", "Error {e} dumping location {:?}",
runtime.location runtime.location
@@ -248,9 +238,8 @@ impl ChainSpec {
} else { } else {
DEFAULT_PRESETS_TO_CHECK.to_vec() DEFAULT_PRESETS_TO_CHECK.to_vec()
}; };
let preset = preset_to_check let preset =
.iter() preset_to_check.iter().find(|preset| presets.iter().any(|item| item == *preset));
.find(|preset| presets.iter().any(|item| item == *preset));
trace!("presets: {:?} - preset to use: {:?}", presets, preset); trace!("presets: {:?} - preset to use: {:?}", presets, preset);
let builder = if let Some(preset) = preset { let builder = if let Some(preset) = preset {
@@ -268,11 +257,7 @@ impl ChainSpec {
.with_genesis_config(default_config) .with_genesis_config(default_config)
}; };
let builder = if let Context::Para { let builder = if let Context::Para { relay_chain: _, para_id: _ } = &self.context {
relay_chain: _,
para_id: _,
} = &self.context
{
builder.with_id(self.chain_spec_name()) builder.with_id(self.chain_spec_name())
} else { } else {
builder builder
@@ -400,8 +385,7 @@ impl ChainSpec {
}, },
} }
self.build_raw_with_command(ns, scoped_fs, raw_spec_path, relay_chain_id) self.build_raw_with_command(ns, scoped_fs, raw_spec_path, relay_chain_id).await?;
.await?;
Ok(()) Ok(())
} }
@@ -430,9 +414,7 @@ impl ChainSpec {
"getting chain-spec as json should work, err: {e}" "getting chain-spec as json should work, err: {e}"
)) ))
})?; })?;
let contents = self let contents = self.ensure_para_fields_in_raw(&contents, relay_chain_id).await?;
.ensure_para_fields_in_raw(&contents, relay_chain_id)
.await?;
self.write_spec(scoped_fs, contents).await?; self.write_spec(scoped_fs, contents).await?;
Ok(()) Ok(())
@@ -449,31 +431,20 @@ impl ChainSpec {
T: FileSystem, T: FileSystem,
{ {
// fallback to use _cmd_ for raw creation // fallback to use _cmd_ for raw creation
let temp_name = format!( let temp_name = format!("temp-build-raw-{}-{}", self.chain_spec_name, rand::random::<u8>());
"temp-build-raw-{}-{}",
self.chain_spec_name,
rand::random::<u8>()
);
let cmd = self let cmd = self
.command .command
.as_ref() .as_ref()
.ok_or(GeneratorError::ChainSpecGeneration( .ok_or(GeneratorError::ChainSpecGeneration("Invalid command".into()))?;
"Invalid command".into(), let maybe_plain_path = self
))?; .maybe_plain_path
let maybe_plain_path =
self.maybe_plain_path
.as_ref() .as_ref()
.ok_or(GeneratorError::ChainSpecGeneration( .ok_or(GeneratorError::ChainSpecGeneration("Invalid plain path".into()))?;
"Invalid plain path".into(),
))?;
// TODO: we should get the full path from the scoped filesystem // TODO: we should get the full path from the scoped filesystem
let chain_spec_path_local = format!( let chain_spec_path_local =
"{}/{}", format!("{}/{}", ns.base_dir().to_string_lossy(), maybe_plain_path.display());
ns.base_dir().to_string_lossy(),
maybe_plain_path.display()
);
// Remote path to be injected // Remote path to be injected
let chain_spec_path_in_pod = format!("{}/{}", NODE_CONFIG_DIR, maybe_plain_path.display()); let chain_spec_path_in_pod = format!("{}/{}", NODE_CONFIG_DIR, maybe_plain_path.display());
// Path in the context of the node, this can be different in the context of the providers (e.g native) // Path in the context of the node, this can be different in the context of the providers (e.g native)
@@ -482,12 +453,7 @@ impl ChainSpec {
chain_spec_path_local.clone() chain_spec_path_local.clone()
} else if ns.capabilities().prefix_with_full_path { } else if ns.capabilities().prefix_with_full_path {
// In native // In native
format!( format!("{}/{}{}", ns.base_dir().to_string_lossy(), &temp_name, &chain_spec_path_in_pod)
"{}/{}{}",
ns.base_dir().to_string_lossy(),
&temp_name,
&chain_spec_path_in_pod
)
} else { } else {
chain_spec_path_in_pod.clone() chain_spec_path_in_pod.clone()
}; };
@@ -521,10 +487,7 @@ impl ChainSpec {
let options = GenerateFilesOptions::with_files( let options = GenerateFilesOptions::with_files(
vec![generate_command], vec![generate_command],
self.image.clone(), self.image.clone(),
&[TransferedFile::new( &[TransferedFile::new(chain_spec_path_local, chain_spec_path_in_pod)],
chain_spec_path_local,
chain_spec_path_in_pod,
)],
expected_path.clone(), expected_path.clone(),
) )
.temp_name(temp_name); .temp_name(temp_name);
@@ -536,9 +499,7 @@ impl ChainSpec {
self.raw_path = Some(raw_spec_path.clone()); self.raw_path = Some(raw_spec_path.clone());
let (content, _) = self.read_spec(scoped_fs).await?; let (content, _) = self.read_spec(scoped_fs).await?;
let content = self let content = self.ensure_para_fields_in_raw(&content, relay_chain_id).await?;
.ensure_para_fields_in_raw(&content, relay_chain_id)
.await?;
self.write_spec(scoped_fs, content).await?; self.write_spec(scoped_fs, content).await?;
Ok(()) Ok(())
@@ -549,11 +510,7 @@ impl ChainSpec {
content: &str, content: &str,
relay_chain_id: Option<Chain>, relay_chain_id: Option<Chain>,
) -> Result<String, GeneratorError> { ) -> Result<String, GeneratorError> {
if let Context::Para { if let Context::Para { relay_chain: _, para_id } = &self.context {
relay_chain: _,
para_id,
} = &self.context
{
let mut chain_spec_json: serde_json::Value = let mut chain_spec_json: serde_json::Value =
serde_json::from_str(content).map_err(|e| { serde_json::from_str(content).map_err(|e| {
GeneratorError::ChainSpecGeneration(format!( GeneratorError::ChainSpecGeneration(format!(
@@ -805,47 +762,27 @@ impl ChainSpec {
clear_authorities(&pointer, &mut chain_spec_json, &self.context); clear_authorities(&pointer, &mut chain_spec_json, &self.context);
let key_type_to_use = if para.is_evm_based { let key_type_to_use =
SessionKeyType::Evm if para.is_evm_based { SessionKeyType::Evm } else { SessionKeyType::Default };
} else {
SessionKeyType::Default
};
// Get validators to add as authorities // Get validators to add as authorities
let validators: Vec<&NodeSpec> = para let validators: Vec<&NodeSpec> =
.collators para.collators.iter().filter(|node| node.is_validator).collect();
.iter()
.filter(|node| node.is_validator)
.collect();
// check chain key types // check chain key types
if chain_spec_json if chain_spec_json.pointer(&format!("{pointer}/session")).is_some() {
.pointer(&format!("{pointer}/session"))
.is_some()
{
add_authorities(&pointer, &mut chain_spec_json, &validators, key_type_to_use); add_authorities(&pointer, &mut chain_spec_json, &validators, key_type_to_use);
} else if chain_spec_json } else if chain_spec_json.pointer(&format!("{pointer}/aura")).is_some() {
.pointer(&format!("{pointer}/aura"))
.is_some()
{
add_aura_authorities(&pointer, &mut chain_spec_json, &validators, KeyType::Aura); add_aura_authorities(&pointer, &mut chain_spec_json, &validators, KeyType::Aura);
} else { } else {
warn!("Can't customize keys, not `session` or `aura` find in the chain-spec file"); warn!("Can't customize keys, not `session` or `aura` find in the chain-spec file");
}; };
// Add nodes to collator // Add nodes to collator
let invulnerables: Vec<&NodeSpec> = para let invulnerables: Vec<&NodeSpec> =
.collators para.collators.iter().filter(|node| node.is_invulnerable).collect();
.iter()
.filter(|node| node.is_invulnerable)
.collect();
add_collator_selection( add_collator_selection(&pointer, &mut chain_spec_json, &invulnerables, key_type_to_use);
&pointer,
&mut chain_spec_json,
&invulnerables,
key_type_to_use,
);
// override `parachainInfo/parachainId` // override `parachainInfo/parachainId`
override_parachain_info(&pointer, &mut chain_spec_json, para.id); override_parachain_info(&pointer, &mut chain_spec_json, para.id);
@@ -920,31 +857,15 @@ impl ChainSpec {
); );
// add staking // add staking
add_staking( add_staking(&pointer, &mut chain_spec_json, &relaychain.nodes, staking_min);
&pointer,
&mut chain_spec_json,
&relaychain.nodes,
staking_min,
);
// Get validators to add as authorities // Get validators to add as authorities
let validators: Vec<&NodeSpec> = relaychain let validators: Vec<&NodeSpec> =
.nodes relaychain.nodes.iter().filter(|node| node.is_validator).collect();
.iter()
.filter(|node| node.is_validator)
.collect();
// check chain key types // check chain key types
if chain_spec_json if chain_spec_json.pointer(&format!("{pointer}/session")).is_some() {
.pointer(&format!("{pointer}/session")) add_authorities(&pointer, &mut chain_spec_json, &validators, SessionKeyType::Stash);
.is_some()
{
add_authorities(
&pointer,
&mut chain_spec_json,
&validators,
SessionKeyType::Stash,
);
} else { } else {
add_aura_authorities(&pointer, &mut chain_spec_json, &validators, KeyType::Aura); add_aura_authorities(&pointer, &mut chain_spec_json, &validators, KeyType::Aura);
add_grandpa_authorities(&pointer, &mut chain_spec_json, &validators, KeyType::Aura); add_grandpa_authorities(&pointer, &mut chain_spec_json, &validators, KeyType::Aura);
@@ -1141,16 +1062,10 @@ where
let paras = val let paras = val
.pointer_mut(paras_pointer) .pointer_mut(paras_pointer)
.ok_or(anyhow!("paras pointer should be valid {paras_pointer:?} "))?; .ok_or(anyhow!("paras pointer should be valid {paras_pointer:?} "))?;
let paras_vec = paras let paras_vec = paras.as_array_mut().ok_or(anyhow!("paras should be an array"))?;
.as_array_mut()
.ok_or(anyhow!("paras should be an array"))?;
let head = scoped_fs let head = scoped_fs.read_to_string(para_genesis_config.state_path.as_ref()).await?;
.read_to_string(para_genesis_config.state_path.as_ref()) let wasm = scoped_fs.read_to_string(para_genesis_config.wasm_path.as_ref()).await?;
.await?;
let wasm = scoped_fs
.read_to_string(para_genesis_config.wasm_path.as_ref())
.await?;
paras_vec.push(json!([ paras_vec.push(json!([
para_genesis_config.id, para_genesis_config.id,
@@ -1190,13 +1105,9 @@ fn percolate_overrides<'a>(
let pointer_parts = pointer.split('/').collect::<Vec<&str>>(); let pointer_parts = pointer.split('/').collect::<Vec<&str>>();
trace!("pointer_parts: {pointer_parts:?}"); trace!("pointer_parts: {pointer_parts:?}");
let top_level = overrides let top_level = overrides.as_object().ok_or_else(|| anyhow!("Overrides must be an object"))?;
.as_object() let top_level_key =
.ok_or_else(|| anyhow!("Overrides must be an object"))?; top_level.keys().next().ok_or_else(|| anyhow!("Invalid override value: {overrides:?}"))?;
let top_level_key = top_level
.keys()
.next()
.ok_or_else(|| anyhow!("Invalid override value: {overrides:?}"))?;
trace!("top_level_key: {top_level_key}"); trace!("top_level_key: {top_level_key}");
let index = pointer_parts.iter().position(|x| *x == top_level_key); let index = pointer_parts.iter().position(|x| *x == top_level_key);
let Some(i) = index else { let Some(i) = index else {
@@ -1215,9 +1126,8 @@ fn percolate_overrides<'a>(
trace!("overrides pointer {p}"); trace!("overrides pointer {p}");
p p
}; };
let overrides_to_use = overrides let overrides_to_use =
.pointer(&p) overrides.pointer(&p).ok_or_else(|| anyhow!("Invalid override value: {overrides:?}"))?;
.ok_or_else(|| anyhow!("Invalid override value: {overrides:?}"))?;
Ok(overrides_to_use) Ok(overrides_to_use)
} }
@@ -1467,14 +1377,7 @@ fn add_hrmp_channels(
if let Some(preopen_hrmp_channels) = val.pointer_mut("/hrmp/preopenHrmpChannels") { if let Some(preopen_hrmp_channels) = val.pointer_mut("/hrmp/preopenHrmpChannels") {
let hrmp_channels = hrmp_channels let hrmp_channels = hrmp_channels
.iter() .iter()
.map(|c| { .map(|c| (c.sender(), c.recipient(), c.max_capacity(), c.max_message_size()))
(
c.sender(),
c.recipient(),
c.max_capacity(),
c.max_message_size(),
)
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
*preopen_hrmp_channels = json!(hrmp_channels); *preopen_hrmp_channels = json!(hrmp_channels);
} else { } else {
@@ -1570,12 +1473,7 @@ fn add_staking(
.get("sr_stash") .get("sr_stash")
.expect("'sr_stash account should be defined for the node. qed") .expect("'sr_stash account should be defined for the node. qed")
.address; .address;
stakers.push(json!([ stakers.push(json!([sr_stash_addr, sr_stash_addr, staking_min, "Validator"]));
sr_stash_addr,
sr_stash_addr,
staking_min,
"Validator"
]));
if node.is_invulnerable { if node.is_invulnerable {
invulnerables.push(sr_stash_addr); invulnerables.push(sr_stash_addr);
@@ -1618,11 +1516,7 @@ fn add_collator_selection(
session_key: SessionKeyType, session_key: SessionKeyType,
) { ) {
if let Some(val) = chain_spec_json.pointer_mut(runtime_config_ptr) { if let Some(val) = chain_spec_json.pointer_mut(runtime_config_ptr) {
let key_type = if let SessionKeyType::Evm = session_key { let key_type = if let SessionKeyType::Evm = session_key { "eth" } else { "sr" };
"eth"
} else {
"sr"
};
let keys: Vec<String> = nodes let keys: Vec<String> = nodes
.iter() .iter()
.map(|node| { .map(|node| {
@@ -1653,13 +1547,13 @@ fn add_collator_selection(
fn generate_balance_map(balances: &serde_json::Value) -> HashMap<String, u128> { fn generate_balance_map(balances: &serde_json::Value) -> HashMap<String, u128> {
// SAFETY: balances is always an array in chain-spec with items [k,v] // SAFETY: balances is always an array in chain-spec with items [k,v]
let balances_map: HashMap<String, u128> = let balances_map: HashMap<String, u128> =
serde_json::from_value::<Vec<(String, u128)>>(balances.to_owned()) serde_json::from_value::<Vec<(String, u128)>>(balances.to_owned()).unwrap().iter().fold(
.unwrap() HashMap::new(),
.iter() |mut memo, balance| {
.fold(HashMap::new(), |mut memo, balance| {
memo.insert(balance.0.clone(), balance.1); memo.insert(balance.0.clone(), balance.1);
memo memo
}); },
);
balances_map balances_map
} }
@@ -1759,9 +1653,8 @@ mod tests {
let pointer = get_runtime_config_pointer(&chain_spec_json).unwrap(); let pointer = get_runtime_config_pointer(&chain_spec_json).unwrap();
clear_authorities(&pointer, &mut chain_spec_json, &Context::Relay); clear_authorities(&pointer, &mut chain_spec_json, &Context::Relay);
let validator_count = chain_spec_json let validator_count =
.pointer(&format!("{pointer}/staking/validatorCount")) chain_spec_json.pointer(&format!("{pointer}/staking/validatorCount")).unwrap();
.unwrap();
assert_eq!(validator_count, &json!(500)); assert_eq!(validator_count, &json!(500));
} }
@@ -1772,9 +1665,8 @@ mod tests {
let pointer = get_runtime_config_pointer(&chain_spec_json).unwrap(); let pointer = get_runtime_config_pointer(&chain_spec_json).unwrap();
clear_authorities(&pointer, &mut chain_spec_json, &Context::Relay); clear_authorities(&pointer, &mut chain_spec_json, &Context::Relay);
let validator_count = chain_spec_json let validator_count =
.pointer(&format!("{pointer}/staking/validatorCount")) chain_spec_json.pointer(&format!("{pointer}/staking/validatorCount")).unwrap();
.unwrap();
assert_eq!(validator_count, &json!(0)); assert_eq!(validator_count, &json!(0));
} }
@@ -1809,9 +1701,7 @@ mod tests {
} }
trace!("chain spec: {chain_spec_json:#?}"); trace!("chain spec: {chain_spec_json:#?}");
assert!(chain_spec_json assert!(chain_spec_json.pointer("/genesis/runtime/balances/devAccounts").is_some());
.pointer("/genesis/runtime/balances/devAccounts")
.is_some());
} }
#[test] #[test]
@@ -1820,23 +1710,14 @@ mod tests {
let mut name = String::from("luca"); let mut name = String::from("luca");
let initial_balance = 1_000_000_000_000_u128; let initial_balance = 1_000_000_000_000_u128;
let seed = format!("//{}{name}", name.remove(0).to_uppercase()); let seed = format!("//{}{name}", name.remove(0).to_uppercase());
let accounts = NodeAccounts { let accounts =
accounts: generators::generate_node_keys(&seed).unwrap(), NodeAccounts { accounts: generators::generate_node_keys(&seed).unwrap(), seed };
seed, let node = NodeSpec { name, accounts, initial_balance, ..Default::default() };
};
let node = NodeSpec {
name,
accounts,
initial_balance,
..Default::default()
};
let nodes = vec![node]; let nodes = vec![node];
add_balances("/genesis/runtime", &mut spec_plain, &nodes, 12, 0); add_balances("/genesis/runtime", &mut spec_plain, &nodes, 12, 0);
let new_balances = spec_plain let new_balances = spec_plain.pointer("/genesis/runtime/balances/balances").unwrap();
.pointer("/genesis/runtime/balances/balances")
.unwrap();
let balances_map = generate_balance_map(new_balances); let balances_map = generate_balance_map(new_balances);
@@ -1844,27 +1725,20 @@ mod tests {
let sr = nodes[0].accounts.accounts.get("sr").unwrap(); let sr = nodes[0].accounts.accounts.get("sr").unwrap();
let sr_stash = nodes[0].accounts.accounts.get("sr_stash").unwrap(); let sr_stash = nodes[0].accounts.accounts.get("sr_stash").unwrap();
assert_eq!(balances_map.get(&sr.address).unwrap(), &initial_balance); assert_eq!(balances_map.get(&sr.address).unwrap(), &initial_balance);
assert_eq!( assert_eq!(balances_map.get(&sr_stash.address).unwrap(), &initial_balance);
balances_map.get(&sr_stash.address).unwrap(),
&initial_balance
);
} }
#[test] #[test]
fn add_balances_ensure_zombie_account() { fn add_balances_ensure_zombie_account() {
let mut spec_plain = chain_spec_test(ROCOCO_LOCAL_PLAIN_TESTING); let mut spec_plain = chain_spec_test(ROCOCO_LOCAL_PLAIN_TESTING);
let balances = spec_plain let balances = spec_plain.pointer("/genesis/runtime/balances/balances").unwrap();
.pointer("/genesis/runtime/balances/balances")
.unwrap();
let balances_map = generate_balance_map(balances); let balances_map = generate_balance_map(balances);
let nodes: Vec<NodeSpec> = vec![]; let nodes: Vec<NodeSpec> = vec![];
add_balances("/genesis/runtime", &mut spec_plain, &nodes, 12, 0); add_balances("/genesis/runtime", &mut spec_plain, &nodes, 12, 0);
let new_balances = spec_plain let new_balances = spec_plain.pointer("/genesis/runtime/balances/balances").unwrap();
.pointer("/genesis/runtime/balances/balances")
.unwrap();
let new_balances_map = generate_balance_map(new_balances); let new_balances_map = generate_balance_map(new_balances);
@@ -1885,16 +1759,9 @@ mod tests {
let mut name = String::from("luca"); let mut name = String::from("luca");
let initial_balance = 1_000_000_000_000_u128; let initial_balance = 1_000_000_000_000_u128;
let seed = format!("//{}{name}", name.remove(0).to_uppercase()); let seed = format!("//{}{name}", name.remove(0).to_uppercase());
let accounts = NodeAccounts { let accounts =
accounts: generators::generate_node_keys(&seed).unwrap(), NodeAccounts { accounts: generators::generate_node_keys(&seed).unwrap(), seed };
seed, let node = NodeSpec { name, accounts, initial_balance, ..Default::default() };
};
let node = NodeSpec {
name,
accounts,
initial_balance,
..Default::default()
};
let nodes = vec![node]; let nodes = vec![node];
add_balances("/genesis/runtime", &mut spec_plain, &nodes, 12, 0); add_balances("/genesis/runtime", &mut spec_plain, &nodes, 12, 0);
@@ -1911,16 +1778,9 @@ mod tests {
let mut name = String::from("luca"); let mut name = String::from("luca");
let initial_balance = 1_000_000_000_000_u128; let initial_balance = 1_000_000_000_000_u128;
let seed = format!("//{}{name}", name.remove(0).to_uppercase()); let seed = format!("//{}{name}", name.remove(0).to_uppercase());
let accounts = NodeAccounts { let accounts =
accounts: generators::generate_node_keys(&seed).unwrap(), NodeAccounts { accounts: generators::generate_node_keys(&seed).unwrap(), seed };
seed, let node = NodeSpec { name, accounts, initial_balance, ..Default::default() };
};
let node = NodeSpec {
name,
accounts,
initial_balance,
..Default::default()
};
let pointer = get_runtime_config_pointer(&chain_spec_json).unwrap(); let pointer = get_runtime_config_pointer(&chain_spec_json).unwrap();
let min = get_staking_min(&pointer, &mut chain_spec_json); let min = get_staking_min(&pointer, &mut chain_spec_json);
@@ -1928,9 +1788,7 @@ mod tests {
let nodes = vec![node]; let nodes = vec![node];
add_staking(&pointer, &mut chain_spec_json, &nodes, min); add_staking(&pointer, &mut chain_spec_json, &nodes, min);
let new_staking = chain_spec_json let new_staking = chain_spec_json.pointer("/genesis/runtimeGenesis/patch/staking").unwrap();
.pointer("/genesis/runtimeGenesis/patch/staking")
.unwrap();
// stakers should be one (with the luca sr_stash accounts) // stakers should be one (with the luca sr_stash accounts)
let sr_stash = nodes[0].accounts.accounts.get("sr_stash").unwrap(); let sr_stash = nodes[0].accounts.accounts.get("sr_stash").unwrap();
@@ -1946,21 +1804,16 @@ mod tests {
let mut spec_plain = chain_spec_test(ROCOCO_LOCAL_PLAIN_TESTING); let mut spec_plain = chain_spec_test(ROCOCO_LOCAL_PLAIN_TESTING);
{ {
let current_hrmp_channels = spec_plain let current_hrmp_channels =
.pointer("/genesis/runtime/hrmp/preopenHrmpChannels") spec_plain.pointer("/genesis/runtime/hrmp/preopenHrmpChannels").unwrap();
.unwrap();
// assert should be empty // assert should be empty
assert_eq!(current_hrmp_channels, &json!([])); assert_eq!(current_hrmp_channels, &json!([]));
} }
let para_100_101 = HrmpChannelConfigBuilder::new() let para_100_101 =
.with_sender(100) HrmpChannelConfigBuilder::new().with_sender(100).with_recipient(101).build();
.with_recipient(101) let para_101_100 =
.build(); HrmpChannelConfigBuilder::new().with_sender(101).with_recipient(100).build();
let para_101_100 = HrmpChannelConfigBuilder::new()
.with_sender(101)
.with_recipient(100)
.build();
let channels = vec![para_100_101, para_101_100]; let channels = vec![para_100_101, para_101_100];
add_hrmp_channels("/genesis/runtime", &mut spec_plain, &channels); add_hrmp_channels("/genesis/runtime", &mut spec_plain, &channels);
@@ -1986,14 +1839,10 @@ mod tests {
*hrmp = json!(serde_json::Value::Null); *hrmp = json!(serde_json::Value::Null);
} }
let para_100_101 = HrmpChannelConfigBuilder::new() let para_100_101 =
.with_sender(100) HrmpChannelConfigBuilder::new().with_sender(100).with_recipient(101).build();
.with_recipient(101) let para_101_100 =
.build(); HrmpChannelConfigBuilder::new().with_sender(101).with_recipient(100).build();
let para_101_100 = HrmpChannelConfigBuilder::new()
.with_sender(101)
.with_recipient(100)
.build();
let channels = vec![para_100_101, para_101_100]; let channels = vec![para_100_101, para_101_100];
add_hrmp_channels("/genesis/runtime", &mut spec_plain, &channels); add_hrmp_channels("/genesis/runtime", &mut spec_plain, &channels);
@@ -2007,15 +1856,9 @@ mod tests {
fn get_node_keys_works() { fn get_node_keys_works() {
let mut name = String::from("luca"); let mut name = String::from("luca");
let seed = format!("//{}{name}", name.remove(0).to_uppercase()); let seed = format!("//{}{name}", name.remove(0).to_uppercase());
let accounts = NodeAccounts { let accounts =
accounts: generators::generate_node_keys(&seed).unwrap(), NodeAccounts { accounts: generators::generate_node_keys(&seed).unwrap(), seed };
seed, let node = NodeSpec { name, accounts, ..Default::default() };
};
let node = NodeSpec {
name,
accounts,
..Default::default()
};
let sr = &node.accounts.accounts["sr"]; let sr = &node.accounts.accounts["sr"];
let keys = [ let keys = [
@@ -2028,10 +1871,7 @@ mod tests {
("aura".into(), sr.address.clone()), ("aura".into(), sr.address.clone()),
("nimbus".into(), sr.address.clone()), ("nimbus".into(), sr.address.clone()),
("vrf".into(), sr.address.clone()), ("vrf".into(), sr.address.clone()),
( ("grandpa".into(), node.accounts.accounts["ed"].address.clone()),
"grandpa".into(),
node.accounts.accounts["ed"].address.clone(),
),
("beefy".into(), node.accounts.accounts["ec"].address.clone()), ("beefy".into(), node.accounts.accounts["ec"].address.clone()),
("eth".into(), node.accounts.accounts["eth"].address.clone()), ("eth".into(), node.accounts.accounts["eth"].address.clone()),
] ]
@@ -2054,15 +1894,9 @@ mod tests {
fn get_node_keys_supports_asset_hub_polkadot() { fn get_node_keys_supports_asset_hub_polkadot() {
let mut name = String::from("luca"); let mut name = String::from("luca");
let seed = format!("//{}{name}", name.remove(0).to_uppercase()); let seed = format!("//{}{name}", name.remove(0).to_uppercase());
let accounts = NodeAccounts { let accounts =
accounts: generators::generate_node_keys(&seed).unwrap(), NodeAccounts { accounts: generators::generate_node_keys(&seed).unwrap(), seed };
seed, let node = NodeSpec { name, accounts, ..Default::default() };
};
let node = NodeSpec {
name,
accounts,
..Default::default()
};
let node_key = get_node_keys(&node, SessionKeyType::default(), false); let node_key = get_node_keys(&node, SessionKeyType::default(), false);
assert_eq!(node_key.2["aura"], node.accounts.accounts["sr"].address); assert_eq!(node_key.2["aura"], node.accounts.accounts["sr"].address);
@@ -31,14 +31,8 @@ impl Default for GenCmdOptions<'_> {
} }
const FLAGS_ADDED_BY_US: [&str; 3] = ["--no-telemetry", "--collator", "--"]; const FLAGS_ADDED_BY_US: [&str; 3] = ["--no-telemetry", "--collator", "--"];
const OPS_ADDED_BY_US: [&str; 6] = [ const OPS_ADDED_BY_US: [&str; 6] =
"--chain", ["--chain", "--name", "--rpc-cors", "--rpc-methods", "--parachain-id", "--node-key"];
"--name",
"--rpc-cors",
"--rpc-methods",
"--parachain-id",
"--node-key",
];
// TODO: can we abstract this and use only one fn (or at least split and reuse in small fns) // TODO: can we abstract this and use only one fn (or at least split and reuse in small fns)
pub fn generate_for_cumulus_node( pub fn generate_for_cumulus_node(
@@ -46,13 +40,7 @@ pub fn generate_for_cumulus_node(
options: GenCmdOptions, options: GenCmdOptions,
para_id: u32, para_id: u32,
) -> (String, Vec<String>) { ) -> (String, Vec<String>) {
let NodeSpec { let NodeSpec { key, args, is_validator, bootnodes_addresses, .. } = node;
key,
args,
is_validator,
bootnodes_addresses,
..
} = node;
let mut tmp_args: Vec<String> = vec!["--node-key".into(), key.clone()]; let mut tmp_args: Vec<String> = vec!["--node-key".into(), key.clone()];
@@ -66,11 +54,8 @@ pub fn generate_for_cumulus_node(
if !bootnodes_addresses.is_empty() { if !bootnodes_addresses.is_empty() {
tmp_args.push("--bootnodes".into()); tmp_args.push("--bootnodes".into());
let bootnodes = bootnodes_addresses let bootnodes =
.iter() bootnodes_addresses.iter().map(|m| m.to_string()).collect::<Vec<String>>().join(" ");
.map(|m| m.to_string())
.collect::<Vec<String>>()
.join(" ");
tmp_args.push(bootnodes) tmp_args.push(bootnodes)
} }
@@ -106,11 +91,8 @@ pub fn generate_for_cumulus_node(
tmp_args.push("--base-path".into()); tmp_args.push("--base-path".into());
tmp_args.push(options.data_path.into()); tmp_args.push(options.data_path.into());
let node_specific_bootnodes: Vec<String> = node let node_specific_bootnodes: Vec<String> =
.bootnodes_addresses node.bootnodes_addresses.iter().map(|b| b.to_string()).collect();
.iter()
.map(|b| b.to_string())
.collect();
let full_bootnodes = [node_specific_bootnodes, options.bootnode_addr].concat(); let full_bootnodes = [node_specific_bootnodes, options.bootnode_addr].concat();
if !full_bootnodes.is_empty() { if !full_bootnodes.is_empty() {
tmp_args.push("--bootnodes".into()); tmp_args.push("--bootnodes".into());
@@ -166,16 +148,12 @@ pub fn generate_for_cumulus_node(
let full_p2p_port = node let full_p2p_port = node
.full_node_p2p_port .full_node_p2p_port
.as_ref() .as_ref()
.expect(&format!( .expect(&format!("full node p2p_port should be specifed: {THIS_IS_A_BUG}"))
"full node p2p_port should be specifed: {THIS_IS_A_BUG}"
))
.0; .0;
let full_prometheus_port = node let full_prometheus_port = node
.full_node_prometheus_port .full_node_prometheus_port
.as_ref() .as_ref()
.expect(&format!( .expect(&format!("full node prometheus_port should be specifed: {THIS_IS_A_BUG}"))
"full node prometheus_port should be specifed: {THIS_IS_A_BUG}"
))
.0; .0;
// full_node: change p2p port if is the default // full_node: change p2p port if is the default
@@ -270,13 +248,7 @@ pub fn generate_for_node(
options: GenCmdOptions, options: GenCmdOptions,
para_id: Option<u32>, para_id: Option<u32>,
) -> (String, Vec<String>) { ) -> (String, Vec<String>) {
let NodeSpec { let NodeSpec { key, args, is_validator, bootnodes_addresses, .. } = node;
key,
args,
is_validator,
bootnodes_addresses,
..
} = node;
let mut tmp_args: Vec<String> = vec![ let mut tmp_args: Vec<String> = vec![
"--node-key".into(), "--node-key".into(),
key.clone(), key.clone(),
@@ -302,11 +274,8 @@ pub fn generate_for_node(
if !bootnodes_addresses.is_empty() { if !bootnodes_addresses.is_empty() {
tmp_args.push("--bootnodes".into()); tmp_args.push("--bootnodes".into());
let bootnodes = bootnodes_addresses let bootnodes =
.iter() bootnodes_addresses.iter().map(|m| m.to_string()).collect::<Vec<String>>().join(" ");
.map(|m| m.to_string())
.collect::<Vec<String>>()
.join(" ");
tmp_args.push(bootnodes) tmp_args.push(bootnodes)
} }
@@ -336,9 +305,8 @@ pub fn generate_for_node(
}) { }) {
let mut parts = listen_val.split('/').collect::<Vec<&str>>(); let mut parts = listen_val.split('/').collect::<Vec<&str>>();
// TODO: move this to error // TODO: move this to error
let port_part = parts let port_part =
.get_mut(4) parts.get_mut(4).expect(&format!("should have at least 5 parts {THIS_IS_A_BUG}"));
.expect(&format!("should have at least 5 parts {THIS_IS_A_BUG}"));
let port_to_use = p2p_port.to_string(); let port_to_use = p2p_port.to_string();
*port_part = port_to_use.as_str(); *port_part = port_to_use.as_str();
parts.join("/") parts.join("/")
@@ -353,11 +321,8 @@ pub fn generate_for_node(
tmp_args.push("--base-path".into()); tmp_args.push("--base-path".into());
tmp_args.push(options.data_path.into()); tmp_args.push(options.data_path.into());
let node_specific_bootnodes: Vec<String> = node let node_specific_bootnodes: Vec<String> =
.bootnodes_addresses node.bootnodes_addresses.iter().map(|b| b.to_string()).collect();
.iter()
.map(|b| b.to_string())
.collect();
let full_bootnodes = [node_specific_bootnodes, options.bootnode_addr].concat(); let full_bootnodes = [node_specific_bootnodes, options.bootnode_addr].concat();
if !full_bootnodes.is_empty() { if !full_bootnodes.is_empty() {
tmp_args.push("--bootnodes".into()); tmp_args.push("--bootnodes".into());
@@ -448,10 +413,8 @@ mod tests {
let mut name = String::from("luca"); let mut name = String::from("luca");
let initial_balance = 1_000_000_000_000_u128; let initial_balance = 1_000_000_000_000_u128;
let seed = format!("//{}{name}", name.remove(0).to_uppercase()); let seed = format!("//{}{name}", name.remove(0).to_uppercase());
let accounts = NodeAccounts { let accounts =
accounts: generators::generate_node_keys(&seed).unwrap(), NodeAccounts { accounts: generators::generate_node_keys(&seed).unwrap(), seed };
seed,
};
let (full_node_p2p_port, full_node_prometheus_port) = if full_node_present { let (full_node_p2p_port, full_node_prometheus_port) = if full_node_present {
( (
Some(generators::generate_node_port(None).unwrap()), Some(generators::generate_node_port(None).unwrap()),
@@ -473,11 +436,8 @@ mod tests {
#[test] #[test]
fn generate_for_native_cumulus_node_works() { fn generate_for_native_cumulus_node_works() {
let node = get_node_spec(true); let node = get_node_spec(true);
let opts = GenCmdOptions { let opts =
use_wrapper: false, GenCmdOptions { use_wrapper: false, is_native: true, ..GenCmdOptions::default() };
is_native: true,
..GenCmdOptions::default()
};
let (program, args) = generate_for_cumulus_node(&node, opts, 1000); let (program, args) = generate_for_cumulus_node(&node, opts, 1000);
assert_eq!(program.as_str(), "polkadot"); assert_eq!(program.as_str(), "polkadot");
@@ -487,28 +447,14 @@ mod tests {
// ensure full node ports // ensure full node ports
let i = args[divider_flag..] let i = args[divider_flag..]
.iter() .iter()
.position(|x| { .position(|x| x == node.full_node_p2p_port.as_ref().unwrap().0.to_string().as_str())
x == node
.full_node_p2p_port
.as_ref()
.unwrap()
.0
.to_string()
.as_str()
})
.unwrap(); .unwrap();
assert_eq!(&args[divider_flag + i - 1], "--port"); assert_eq!(&args[divider_flag + i - 1], "--port");
let i = args[divider_flag..] let i = args[divider_flag..]
.iter() .iter()
.position(|x| { .position(|x| {
x == node x == node.full_node_prometheus_port.as_ref().unwrap().0.to_string().as_str()
.full_node_prometheus_port
.as_ref()
.unwrap()
.0
.to_string()
.as_str()
}) })
.unwrap(); .unwrap();
assert_eq!(&args[divider_flag + i - 1], "--prometheus-port"); assert_eq!(&args[divider_flag + i - 1], "--prometheus-port");
@@ -520,11 +466,8 @@ mod tests {
fn generate_for_native_cumulus_node_rpc_external_is_not_removed_if_is_set_by_user() { fn generate_for_native_cumulus_node_rpc_external_is_not_removed_if_is_set_by_user() {
let mut node = get_node_spec(true); let mut node = get_node_spec(true);
node.args.push("--unsafe-rpc-external".into()); node.args.push("--unsafe-rpc-external".into());
let opts = GenCmdOptions { let opts =
use_wrapper: false, GenCmdOptions { use_wrapper: false, is_native: true, ..GenCmdOptions::default() };
is_native: true,
..GenCmdOptions::default()
};
let (_, args) = generate_for_cumulus_node(&node, opts, 1000); let (_, args) = generate_for_cumulus_node(&node, opts, 1000);
@@ -534,11 +477,8 @@ mod tests {
#[test] #[test]
fn generate_for_non_native_cumulus_node_works() { fn generate_for_non_native_cumulus_node_works() {
let node = get_node_spec(true); let node = get_node_spec(true);
let opts = GenCmdOptions { let opts =
use_wrapper: false, GenCmdOptions { use_wrapper: false, is_native: false, ..GenCmdOptions::default() };
is_native: false,
..GenCmdOptions::default()
};
let (program, args) = generate_for_cumulus_node(&node, opts, 1000); let (program, args) = generate_for_cumulus_node(&node, opts, 1000);
assert_eq!(program.as_str(), "polkadot"); assert_eq!(program.as_str(), "polkadot");
@@ -548,46 +488,27 @@ mod tests {
// ensure full node ports // ensure full node ports
let i = args[divider_flag..] let i = args[divider_flag..]
.iter() .iter()
.position(|x| { .position(|x| x == node.full_node_p2p_port.as_ref().unwrap().0.to_string().as_str())
x == node
.full_node_p2p_port
.as_ref()
.unwrap()
.0
.to_string()
.as_str()
})
.unwrap(); .unwrap();
assert_eq!(&args[divider_flag + i - 1], "--port"); assert_eq!(&args[divider_flag + i - 1], "--port");
let i = args[divider_flag..] let i = args[divider_flag..]
.iter() .iter()
.position(|x| { .position(|x| {
x == node x == node.full_node_prometheus_port.as_ref().unwrap().0.to_string().as_str()
.full_node_prometheus_port
.as_ref()
.unwrap()
.0
.to_string()
.as_str()
}) })
.unwrap(); .unwrap();
assert_eq!(&args[divider_flag + i - 1], "--prometheus-port"); assert_eq!(&args[divider_flag + i - 1], "--prometheus-port");
// we expect to find this arg in collator node part // we expect to find this arg in collator node part
assert!(&args[0..divider_flag] assert!(&args[0..divider_flag].iter().any(|arg| arg == "--unsafe-rpc-external"));
.iter()
.any(|arg| arg == "--unsafe-rpc-external"));
} }
#[test] #[test]
fn generate_for_native_node_rpc_external_works() { fn generate_for_native_node_rpc_external_works() {
let node = get_node_spec(false); let node = get_node_spec(false);
let opts = GenCmdOptions { let opts =
use_wrapper: false, GenCmdOptions { use_wrapper: false, is_native: true, ..GenCmdOptions::default() };
is_native: true,
..GenCmdOptions::default()
};
let (program, args) = generate_for_node(&node, opts, Some(1000)); let (program, args) = generate_for_node(&node, opts, Some(1000));
assert_eq!(program.as_str(), "polkadot"); assert_eq!(program.as_str(), "polkadot");
@@ -598,11 +519,8 @@ mod tests {
#[test] #[test]
fn generate_for_non_native_node_rpc_external_works() { fn generate_for_non_native_node_rpc_external_works() {
let node = get_node_spec(false); let node = get_node_spec(false);
let opts = GenCmdOptions { let opts =
use_wrapper: false, GenCmdOptions { use_wrapper: false, is_native: false, ..GenCmdOptions::default() };
is_native: false,
..GenCmdOptions::default()
};
let (program, args) = generate_for_node(&node, opts, Some(1000)); let (program, args) = generate_for_node(&node, opts, Some(1000));
assert_eq!(program.as_str(), "polkadot"); assert_eq!(program.as_str(), "polkadot");
@@ -613,22 +531,16 @@ mod tests {
#[test] #[test]
fn test_arg_removal_removes_insecure_validator_flag() { fn test_arg_removal_removes_insecure_validator_flag() {
let mut node = get_node_spec(false); let mut node = get_node_spec(false);
node.args node.args.push(Arg::Flag("-:--insecure-validator-i-know-what-i-do".into()));
.push(Arg::Flag("-:--insecure-validator-i-know-what-i-do".into()));
node.is_validator = true; node.is_validator = true;
node.available_args_output = Some("--insecure-validator-i-know-what-i-do".to_string()); node.available_args_output = Some("--insecure-validator-i-know-what-i-do".to_string());
let opts = GenCmdOptions { let opts =
use_wrapper: false, GenCmdOptions { use_wrapper: false, is_native: true, ..GenCmdOptions::default() };
is_native: true,
..GenCmdOptions::default()
};
let (program, args) = generate_for_node(&node, opts, Some(1000)); let (program, args) = generate_for_node(&node, opts, Some(1000));
assert_eq!(program.as_str(), "polkadot"); assert_eq!(program.as_str(), "polkadot");
assert!(args.iter().any(|arg| arg == "--validator")); assert!(args.iter().any(|arg| arg == "--validator"));
assert!(!args assert!(!args.iter().any(|arg| arg == "--insecure-validator-i-know-what-i-do"));
.iter()
.any(|arg| arg == "--insecure-validator-i-know-what-i-do"));
} }
} }
@@ -29,13 +29,7 @@ mod tests {
fn generate_for_alice() { fn generate_for_alice() {
let s = "alice"; let s = "alice";
let (key, peer_id) = generate(s).unwrap(); let (key, peer_id) = generate(s).unwrap();
assert_eq!( assert_eq!(&key, "2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90");
&key, assert_eq!(&peer_id, "12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm");
"2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90"
);
assert_eq!(
&peer_id,
"12D3KooWQCkBm1BYtkHpocxCwMgR8yjitEeHGx8spzcDLGt2gkBm"
);
} }
} }
@@ -1,4 +1,6 @@
use pezsp_core::{crypto::SecretStringError, ecdsa, ed25519, keccak_256, sr25519, Pair, H160, H256}; use pezsp_core::{
crypto::SecretStringError, ecdsa, ed25519, keccak_256, sr25519, Pair, H160, H256,
};
use super::errors::GeneratorError; use super::errors::GeneratorError;
use crate::shared::types::{Accounts, NodeAccount}; use crate::shared::types::{Accounts, NodeAccount};
@@ -126,26 +128,14 @@ mod tests {
let ec = pair.get("ec").unwrap(); let ec = pair.get("ec").unwrap();
let eth = pair.get("eth").unwrap(); let eth = pair.get("eth").unwrap();
assert_eq!( assert_eq!(sr.address, "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY");
sr.address, assert_eq!(sr_stash.address, "5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY");
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" assert_eq!(ed.address, "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu");
);
assert_eq!(
sr_stash.address,
"5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY"
);
assert_eq!(
ed.address,
"5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu"
);
assert_eq!( assert_eq!(
format!("0x{}", ec.public_key), format!("0x{}", ec.public_key),
"0x020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a1" "0x020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a1"
); );
assert_eq!( assert_eq!(format!("0x{}", eth.public_key), "0xe04cc55ebee1cbce552f250e85c57b70b2e2625b")
format!("0x{}", eth.public_key),
"0xe04cc55ebee1cbce552f250e85c57b70b2e2625b"
)
} }
} }
@@ -71,10 +71,7 @@ fn generate_keystore_filename(key_type: &KeystoreKeyType, acc: &NodeAccounts) ->
let pk = acc let pk = acc
.accounts .accounts
.get(account_key) .get(account_key)
.expect(&format!( .expect(&format!("Key '{}' should be set for node {THIS_IS_A_BUG}", account_key))
"Key '{}' should be set for node {THIS_IS_A_BUG}",
account_key
))
.public_key .public_key
.as_str(); .as_str();
@@ -92,22 +89,10 @@ mod tests {
fn create_test_accounts() -> NodeAccounts { fn create_test_accounts() -> NodeAccounts {
let mut accounts = HashMap::new(); let mut accounts = HashMap::new();
accounts.insert( accounts.insert("sr".to_string(), NodeAccount::new("sr_address", "sr_public_key"));
"sr".to_string(), accounts.insert("ed".to_string(), NodeAccount::new("ed_address", "ed_public_key"));
NodeAccount::new("sr_address", "sr_public_key"), accounts.insert("ec".to_string(), NodeAccount::new("ec_address", "ec_public_key"));
); NodeAccounts { seed: "//Alice".to_string(), accounts }
accounts.insert(
"ed".to_string(),
NodeAccount::new("ed_address", "ed_public_key"),
);
accounts.insert(
"ec".to_string(),
NodeAccount::new("ec_address", "ec_public_key"),
);
NodeAccounts {
seed: "//Alice".to_string(),
accounts,
}
} }
fn create_test_fs() -> InMemoryFileSystem { fn create_test_fs() -> InMemoryFileSystem {
@@ -133,10 +118,8 @@ mod tests {
assert!(filenames.len() > 10); assert!(filenames.len() > 10);
let filename_strs: Vec<String> = filenames let filename_strs: Vec<String> =
.iter() filenames.iter().map(|p| p.to_string_lossy().to_string()).collect();
.map(|p| p.to_string_lossy().to_string())
.collect();
// Check that aura key is generated (hex of "aura" is 61757261) // Check that aura key is generated (hex of "aura" is 61757261)
assert!(filename_strs.iter().any(|f| f.starts_with("61757261"))); assert!(filename_strs.iter().any(|f| f.starts_with("61757261")));
@@ -162,10 +145,8 @@ mod tests {
let filenames = res.unwrap(); let filenames = res.unwrap();
assert_eq!(filenames.len(), 2); assert_eq!(filenames.len(), 2);
let filename_strs: Vec<String> = filenames let filename_strs: Vec<String> =
.iter() filenames.iter().map(|p| p.to_string_lossy().to_string()).collect();
.map(|p| p.to_string_lossy().to_string())
.collect();
// audi uses sr scheme by default // audi uses sr scheme by default
assert!(filename_strs assert!(filename_strs
@@ -221,27 +202,13 @@ mod tests {
for tc in test_cases { for tc in test_cases {
let accounts = create_test_accounts(); let accounts = create_test_accounts();
let fs = create_test_fs(); let fs = create_test_fs();
let scoped_fs = ScopedFilesystem { let scoped_fs = ScopedFilesystem { fs: &fs, base_dir: "/tmp/test" };
fs: &fs,
base_dir: "/tmp/test",
};
let key_types: Vec<&str> = tc.key_types.clone(); let key_types: Vec<&str> = tc.key_types.clone();
let res = generate( let res =
&accounts, generate(&accounts, "node1", &scoped_fs, tc.asset_hub_polkadot, key_types).await;
"node1",
&scoped_fs,
tc.asset_hub_polkadot,
key_types,
)
.await;
assert!( assert!(res.is_ok(), "[{}] Expected Ok but got: {:?}", tc.name, res.err());
res.is_ok(),
"[{}] Expected Ok but got: {:?}",
tc.name,
res.err()
);
let filenames = res.unwrap(); let filenames = res.unwrap();
assert_eq!(filenames.len(), 1, "[{}] Expected 1 file", tc.name); assert_eq!(filenames.len(), 1, "[{}] Expected 1 file", tc.name);
@@ -268,10 +235,7 @@ mod tests {
async fn generate_ignores_invalid_key_specs_and_uses_defaults() { async fn generate_ignores_invalid_key_specs_and_uses_defaults() {
let accounts = create_test_accounts(); let accounts = create_test_accounts();
let fs = create_test_fs(); let fs = create_test_fs();
let scoped_fs = ScopedFilesystem { let scoped_fs = ScopedFilesystem { fs: &fs, base_dir: "/tmp/test" };
fs: &fs,
base_dir: "/tmp/test",
};
let key_types = vec![ let key_types = vec![
"invalid", // Too long "invalid", // Too long
@@ -58,10 +58,7 @@ pub struct KeystoreKeyType {
impl KeystoreKeyType { impl KeystoreKeyType {
pub fn new(key_type: impl Into<String>, scheme: KeyScheme) -> Self { pub fn new(key_type: impl Into<String>, scheme: KeyScheme) -> Self {
Self { Self { key_type: key_type.into(), scheme }
key_type: key_type.into(),
scheme,
}
} }
} }
@@ -160,9 +157,7 @@ pub fn get_default_keystore_key_types(is_asset_hub_polkadot: bool) -> Vec<Keysto
default_keys default_keys
.iter() .iter()
.filter_map(|key_type| { .filter_map(|key_type| {
predefined_schemes predefined_schemes.get(*key_type).map(|scheme| KeystoreKeyType::new(*key_type, *scheme))
.get(*key_type)
.map(|scheme| KeystoreKeyType::new(*key_type, *scheme))
}) })
.collect() .collect()
} }
@@ -41,12 +41,7 @@ impl ParaArtifact {
artifact_type: ParaArtifactType, artifact_type: ParaArtifactType,
build_option: ParaArtifactBuildOption, build_option: ParaArtifactBuildOption,
) -> Self { ) -> Self {
Self { Self { artifact_type, build_option, artifact_path: None, image: None }
artifact_type,
build_option,
artifact_path: None,
image: None,
}
} }
pub(crate) fn image(mut self, image: Option<String>) -> Self { pub(crate) fn image(mut self, image: Option<String>) -> Self {
@@ -78,10 +73,7 @@ impl ParaArtifact {
}, },
ParaArtifactBuildOption::Command(cmd) => (cmd, &vec![]), ParaArtifactBuildOption::Command(cmd) => (cmd, &vec![]),
ParaArtifactBuildOption::CommandWithCustomArgs(cmd_with_custom_args) => { ParaArtifactBuildOption::CommandWithCustomArgs(cmd_with_custom_args) => {
( (&cmd_with_custom_args.cmd().as_str().to_string(), cmd_with_custom_args.args())
&cmd_with_custom_args.cmd().as_str().to_string(),
cmd_with_custom_args.args(),
)
// (cmd.cmd_as_str().to_string(), cmd.1) // (cmd.cmd_as_str().to_string(), cmd.1)
}, },
}; };
@@ -103,11 +95,8 @@ impl ParaArtifact {
chain_spec_path.as_ref().to_string_lossy() chain_spec_path.as_ref().to_string_lossy()
); );
// Remote path to be injected // Remote path to be injected
let chain_spec_path_in_pod = format!( let chain_spec_path_in_pod =
"{}/{}", format!("{}/{}", NODE_CONFIG_DIR, chain_spec_path.as_ref().to_string_lossy());
NODE_CONFIG_DIR,
chain_spec_path.as_ref().to_string_lossy()
);
// Path in the context of the node, this can be different in the context of the providers (e.g native) // Path in the context of the node, this can be different in the context of the providers (e.g native)
let chain_spec_path_in_args = if ns.capabilities().prefix_with_full_path { let chain_spec_path_in_args = if ns.capabilities().prefix_with_full_path {
// In native // In native
@@ -140,10 +129,7 @@ impl ParaArtifact {
} }
} }
vec![TransferedFile::new( vec![TransferedFile::new(chain_spec_path_local, chain_spec_path_in_pod)]
chain_spec_path_local,
chain_spec_path_in_pod,
)]
} else { } else {
vec![] vec![]
}; };
@@ -19,9 +19,7 @@ pub fn generate(port: Option<Port>) -> Result<ParkedPort, GeneratorError> {
.map_err(|_e| GeneratorError::PortGeneration(port, "Can't bind".into()))?; .map_err(|_e| GeneratorError::PortGeneration(port, "Can't bind".into()))?;
let port = listener let port = listener
.local_addr() .local_addr()
.expect(&format!( .expect(&format!("We should always get the local_addr from the listener {THIS_IS_A_BUG}"))
"We should always get the local_addr from the listener {THIS_IS_A_BUG}"
))
.port(); .port();
Ok(ParkedPort::new(port, listener)) Ok(ParkedPort::new(port, listener))
} }
+39 -122
View File
@@ -61,10 +61,7 @@ where
T: FileSystem + Sync + Send + Clone, T: FileSystem + Sync + Send + Clone,
{ {
pub fn new(filesystem: T, provider: DynProvider) -> Self { pub fn new(filesystem: T, provider: DynProvider) -> Self {
Self { Self { filesystem, provider }
filesystem,
provider,
}
} }
pub async fn spawn( pub async fn spawn(
@@ -74,10 +71,8 @@ where
let global_timeout = network_config.global_settings().network_spawn_timeout(); let global_timeout = network_config.global_settings().network_spawn_timeout();
let network_spec = NetworkSpec::from_config(&network_config).await?; let network_spec = NetworkSpec::from_config(&network_config).await?;
let res = timeout( let res =
Duration::from_secs(global_timeout.into()), timeout(Duration::from_secs(global_timeout.into()), self.spawn_inner(network_spec))
self.spawn_inner(network_spec),
)
.await .await
.map_err(|_| OrchestratorError::GlobalTimeOut(global_timeout)); .map_err(|_| OrchestratorError::GlobalTimeOut(global_timeout));
res? res?
@@ -88,10 +83,8 @@ where
network_spec: NetworkSpec, network_spec: NetworkSpec,
) -> Result<Network<T>, OrchestratorError> { ) -> Result<Network<T>, OrchestratorError> {
let global_timeout = network_spec.global_settings.network_spawn_timeout(); let global_timeout = network_spec.global_settings.network_spawn_timeout();
let res = timeout( let res =
Duration::from_secs(global_timeout as u64), timeout(Duration::from_secs(global_timeout as u64), self.spawn_inner(network_spec))
self.spawn_inner(network_spec),
)
.await .await
.map_err(|_| OrchestratorError::GlobalTimeOut(global_timeout)); .map_err(|_| OrchestratorError::GlobalTimeOut(global_timeout));
res? res?
@@ -108,10 +101,7 @@ where
let zombie_json: serde_json::Value = serde_json::from_str(&zombie_json_content)?; let zombie_json: serde_json::Value = serde_json::from_str(&zombie_json_content)?;
info!("recreating namespace..."); info!("recreating namespace...");
let ns: DynNamespace = self let ns: DynNamespace = self.provider.create_namespace_from_json(&zombie_json).await?;
.provider
.create_namespace_from_json(&zombie_json)
.await?;
info!("recreating relaychain..."); info!("recreating relaychain...");
let (relay, initial_spec) = let (relay, initial_spec) =
@@ -159,9 +149,7 @@ where
// create namespace // create namespace
let ns = if let Some(base_dir) = network_spec.global_settings.base_dir() { let ns = if let Some(base_dir) = network_spec.global_settings.base_dir() {
self.provider self.provider.create_namespace_with_base_dir(base_dir).await?
.create_namespace_with_base_dir(base_dir)
.await?
} else { } else {
self.provider.create_namespace().await? self.provider.create_namespace().await?
}; };
@@ -175,26 +163,16 @@ where
info!("🕰 start time: {:?}", start_time); info!("🕰 start time: {:?}", start_time);
info!("⚙️ spawn concurrency: {spawn_concurrency} (limited by tokens: {limited_by_tokens})"); info!("⚙️ spawn concurrency: {spawn_concurrency} (limited by tokens: {limited_by_tokens})");
network_spec network_spec.populate_nodes_available_args(ns.clone()).await?;
.populate_nodes_available_args(ns.clone())
.await?;
let base_dir = ns.base_dir().to_string_lossy(); let base_dir = ns.base_dir().to_string_lossy();
let scoped_fs = ScopedFilesystem::new(&self.filesystem, &base_dir); let scoped_fs = ScopedFilesystem::new(&self.filesystem, &base_dir);
// Create chain-spec for relaychain // Create chain-spec for relaychain
network_spec network_spec.relaychain.chain_spec.build(&ns, &scoped_fs).await?;
.relaychain
.chain_spec
.build(&ns, &scoped_fs)
.await?;
debug!("relaychain spec built!"); debug!("relaychain spec built!");
// Create parachain artifacts (chain-spec, wasm, state) // Create parachain artifacts (chain-spec, wasm, state)
let relay_chain_id = network_spec let relay_chain_id = network_spec.relaychain.chain_spec.read_chain_id(&scoped_fs).await?;
.relaychain
.chain_spec
.read_chain_id(&scoped_fs)
.await?;
let relay_chain_name = network_spec.relaychain.chain.as_str().to_owned(); let relay_chain_name = network_spec.relaychain.chain.as_str().to_owned();
let base_dir_exists = network_spec.global_settings.base_dir().is_some(); let base_dir_exists = network_spec.global_settings.base_dir().is_some();
@@ -233,19 +211,11 @@ where
.await?; .await?;
// Build raw version // Build raw version
network_spec network_spec.relaychain.chain_spec.build_raw(&ns, &scoped_fs, None).await?;
.relaychain
.chain_spec
.build_raw(&ns, &scoped_fs, None)
.await?;
// override wasm if needed // override wasm if needed
if let Some(ref wasm_override) = network_spec.relaychain.wasm_override { if let Some(ref wasm_override) = network_spec.relaychain.wasm_override {
network_spec network_spec.relaychain.chain_spec.override_code(&scoped_fs, wasm_override).await?;
.relaychain
.chain_spec
.override_code(&scoped_fs, wasm_override)
.await?;
} }
// override raw spec if needed // override raw spec if needed
@@ -276,10 +246,7 @@ where
}; };
let global_files_to_inject = vec![TransferedFile::new( let global_files_to_inject = vec![TransferedFile::new(
PathBuf::from(format!( PathBuf::from(format!("{}/{relay_chain_name}.json", ns.base_dir().to_string_lossy())),
"{}/{relay_chain_name}.json",
ns.base_dir().to_string_lossy()
)),
PathBuf::from(format!("/cfg/{relay_chain_name}.json")), PathBuf::from(format!("/cfg/{relay_chain_name}.json")),
)]; )];
@@ -339,11 +306,7 @@ where
} }
// Add the bootnodes to the relaychain spec file and ctx // Add the bootnodes to the relaychain spec file and ctx
network_spec network_spec.relaychain.chain_spec.add_bootnodes(&scoped_fs, &bootnodes_addr).await?;
.relaychain
.chain_spec
.add_bootnodes(&scoped_fs, &bootnodes_addr)
.await?;
ctx.bootnodes_addr = &bootnodes_addr; ctx.bootnodes_addr = &bootnodes_addr;
@@ -436,9 +399,7 @@ where
} }
if let Some(para_chain_spec) = para.chain_spec.as_ref() { if let Some(para_chain_spec) = para.chain_spec.as_ref() {
para_chain_spec para_chain_spec.add_bootnodes(&scoped_fs, &bootnodes_addr).await?;
.add_bootnodes(&scoped_fs, &bootnodes_addr)
.await?;
} }
ctx_para.bootnodes_addr = &bootnodes_addr; ctx_para.bootnodes_addr = &bootnodes_addr;
@@ -527,9 +488,7 @@ where
warn!("⚠️ Error getting start_time timestamp"); warn!("⚠️ Error getting start_time timestamp");
} }
scoped_fs scoped_fs.write("zombie.json", serde_json::to_string_pretty(&zombie_json)?).await?;
.write("zombie.json", serde_json::to_string_pretty(&zombie_json)?)
.await?;
if network_spec.global_settings.tear_down_on_failure() { if network_spec.global_settings.tear_down_on_failure() {
network.spawn_watching_task(); network.spawn_watching_task();
@@ -551,11 +510,8 @@ async fn recreate_network_nodes_from_json(
let mut nodes = Vec::with_capacity(raw_nodes.len()); let mut nodes = Vec::with_capacity(raw_nodes.len());
for raw in raw_nodes { for raw in raw_nodes {
// validate provider tag // validate provider tag
let provider_tag = raw let provider_tag =
.inner raw.inner.get("provider_tag").and_then(|v| v.as_str()).ok_or_else(|| {
.get("provider_tag")
.and_then(|v| v.as_str())
.ok_or_else(|| {
OrchestratorError::InvalidConfig("Missing `provider_tag` in inner node JSON".into()) OrchestratorError::InvalidConfig("Missing `provider_tag` in inner node JSON".into())
})?; })?;
@@ -587,9 +543,7 @@ async fn recreate_relaychain_from_json(
) -> Result<(Relaychain, NetworkSpec), OrchestratorError> { ) -> Result<(Relaychain, NetworkSpec), OrchestratorError> {
let relay_json = zombie_json let relay_json = zombie_json
.get("relay") .get("relay")
.ok_or(OrchestratorError::InvalidConfig( .ok_or(OrchestratorError::InvalidConfig("Missing `relay` field in zombie.json".into()))?
"Missing `relay` field in zombie.json".into(),
))?
.clone(); .clone();
let mut relay_raw: RawRelaychain = serde_json::from_value(relay_json)?; let mut relay_raw: RawRelaychain = serde_json::from_value(relay_json)?;
@@ -805,10 +759,8 @@ fn spawn_concurrency_from_env() -> Option<usize> {
} }
fn calculate_concurrency(spec: &NetworkSpec) -> Result<(usize, bool), anyhow::Error> { fn calculate_concurrency(spec: &NetworkSpec) -> Result<(usize, bool), anyhow::Error> {
let desired_spawn_concurrency = match ( let desired_spawn_concurrency =
spawn_concurrency_from_env(), match (spawn_concurrency_from_env(), spec.global_settings.spawn_concurrency()) {
spec.global_settings.spawn_concurrency(),
) {
(Some(n), _) => Some(n), (Some(n), _) => Some(n),
(None, Some(n)) => Some(n), (None, Some(n)) => Some(n),
_ => None, _ => None,
@@ -843,10 +795,7 @@ fn calculate_concurrency(spec: &NetworkSpec) -> Result<(usize, bool), anyhow::Er
fn dependency_levels_among<'a>( fn dependency_levels_among<'a>(
nodes: &'a [&'a NodeSpec], nodes: &'a [&'a NodeSpec],
) -> Result<Vec<Vec<&'a NodeSpec>>, OrchestratorError> { ) -> Result<Vec<Vec<&'a NodeSpec>>, OrchestratorError> {
let by_name = nodes let by_name = nodes.iter().map(|n| (n.name.as_str(), *n)).collect::<HashMap<_, _>>();
.iter()
.map(|n| (n.name.as_str(), *n))
.collect::<HashMap<_, _>>();
let mut graph = HashMap::with_capacity(nodes.len()); let mut graph = HashMap::with_capacity(nodes.len());
let mut indegree = HashMap::with_capacity(nodes.len()); let mut indegree = HashMap::with_capacity(nodes.len());
@@ -900,15 +849,12 @@ fn dependency_levels_among<'a>(
let mut current_level = Vec::with_capacity(level_size); let mut current_level = Vec::with_capacity(level_size);
for _ in 0..level_size { for _ in 0..level_size {
let n = queue let n = queue.pop_front().expect(&format!("{QUEUE_NOT_EMPTY} {THIS_IS_A_BUG}"));
.pop_front()
.expect(&format!("{QUEUE_NOT_EMPTY} {THIS_IS_A_BUG}"));
current_level.push(n); current_level.push(n);
processed_count += 1; processed_count += 1;
for &neighbour in graph for &neighbour in
.get(n.name.as_str()) graph.get(n.name.as_str()).expect(&format!("{GRAPH_CONTAINS_NAME} {THIS_IS_A_BUG}"))
.expect(&format!("{GRAPH_CONTAINS_NAME} {THIS_IS_A_BUG}"))
{ {
let neighbour_indegree = indegree let neighbour_indegree = indegree
.get_mut(neighbour.name.as_str()) .get_mut(neighbour.name.as_str())
@@ -955,15 +901,10 @@ impl<'a, FS: FileSystem> ScopedFilesystem<'a, FS> {
async fn copy_files(&self, files: Vec<&TransferedFile>) -> Result<(), FileSystemError> { async fn copy_files(&self, files: Vec<&TransferedFile>) -> Result<(), FileSystemError> {
for file in files { for file in files {
let full_remote_path = PathBuf::from(format!( let full_remote_path =
"{}/{}", PathBuf::from(format!("{}/{}", self.base_dir, file.remote_path.to_string_lossy()));
self.base_dir,
file.remote_path.to_string_lossy()
));
trace!("coping file: {file}"); trace!("coping file: {file}");
self.fs self.fs.copy(file.local_path.as_path(), full_remote_path).await?;
.copy(file.local_path.as_path(), full_remote_path)
.await?;
} }
Ok(()) Ok(())
} }
@@ -993,20 +934,12 @@ impl<'a, FS: FileSystem> ScopedFilesystem<'a, FS> {
} }
async fn create_dir(&self, path: impl AsRef<Path>) -> Result<(), FileSystemError> { async fn create_dir(&self, path: impl AsRef<Path>) -> Result<(), FileSystemError> {
let path = PathBuf::from(format!( let path = PathBuf::from(format!("{}/{}", self.base_dir, path.as_ref().to_string_lossy()));
"{}/{}",
self.base_dir,
path.as_ref().to_string_lossy()
));
self.fs.create_dir(path).await self.fs.create_dir(path).await
} }
async fn create_dir_all(&self, path: impl AsRef<Path>) -> Result<(), FileSystemError> { async fn create_dir_all(&self, path: impl AsRef<Path>) -> Result<(), FileSystemError> {
let path = PathBuf::from(format!( let path = PathBuf::from(format!("{}/{}", self.base_dir, path.as_ref().to_string_lossy()));
"{}/{}",
self.base_dir,
path.as_ref().to_string_lossy()
));
self.fs.create_dir_all(path).await self.fs.create_dir_all(path).await
} }
@@ -1110,27 +1043,17 @@ mod tests {
} }
fn get_node_with_dependencies(name: &str, dependencies: Option<Vec<&NodeSpec>>) -> NodeSpec { fn get_node_with_dependencies(name: &str, dependencies: Option<Vec<&NodeSpec>>) -> NodeSpec {
let mut spec = NodeSpec { let mut spec = NodeSpec { name: name.to_string(), ..Default::default() };
name: name.to_string(),
..Default::default()
};
if let Some(dependencies) = dependencies { if let Some(dependencies) = dependencies {
for node in dependencies { for node in dependencies {
spec.args.push( spec.args.push(format!("{{{{ZOMBIE:{}:someField}}}}", node.name).as_str().into());
format!("{{{{ZOMBIE:{}:someField}}}}", node.name)
.as_str()
.into(),
);
} }
} }
spec spec
} }
fn verify_levels(actual_levels: Vec<Vec<&NodeSpec>>, expected_levels: Vec<Vec<&str>>) { fn verify_levels(actual_levels: Vec<Vec<&NodeSpec>>, expected_levels: Vec<Vec<&str>>) {
actual_levels actual_levels.iter().zip(expected_levels).for_each(|(actual_level, expected_level)| {
.iter()
.zip(expected_levels)
.for_each(|(actual_level, expected_level)| {
assert_eq!(actual_level.len(), expected_level.len()); assert_eq!(actual_level.len(), expected_level.len());
actual_level actual_level
.iter() .iter()
@@ -1218,10 +1141,8 @@ mod tests {
let network_config = generate(false, Some("cargo")).unwrap(); let network_config = generate(false, Some("cargo")).unwrap();
let mut spec = NetworkSpec::from_config(&network_config).await.unwrap(); let mut spec = NetworkSpec::from_config(&network_config).await.unwrap();
let global_settings = GlobalSettingsBuilder::new() let global_settings =
.with_spawn_concurrency(4) GlobalSettingsBuilder::new().with_spawn_concurrency(4).build().unwrap();
.build()
.unwrap();
spec.set_global_settings(global_settings); spec.set_global_settings(global_settings);
let (concurrency, limited) = calculate_concurrency(&spec).unwrap(); let (concurrency, limited) = calculate_concurrency(&spec).unwrap();
@@ -1237,15 +1158,12 @@ mod tests {
let network_config = generate(false, Some("cargo")).unwrap(); let network_config = generate(false, Some("cargo")).unwrap();
let mut spec = NetworkSpec::from_config(&network_config).await.unwrap(); let mut spec = NetworkSpec::from_config(&network_config).await.unwrap();
let global_settings = GlobalSettingsBuilder::new() let global_settings =
.with_spawn_concurrency(4) GlobalSettingsBuilder::new().with_spawn_concurrency(4).build().unwrap();
.build()
.unwrap();
spec.set_global_settings(global_settings); spec.set_global_settings(global_settings);
let node = spec.relaychain.nodes.first_mut().unwrap(); let node = spec.relaychain.nodes.first_mut().unwrap();
node.args node.args.push("--bootnodes {{ZOMBIE:bob:multiAddress')}}".into());
.push("--bootnodes {{ZOMBIE:bob:multiAddress')}}".into());
let (concurrency, limited) = calculate_concurrency(&spec).unwrap(); let (concurrency, limited) = calculate_concurrency(&spec).unwrap();
assert_eq!(concurrency, 1); assert_eq!(concurrency, 1);
assert!(limited); assert!(limited);
@@ -1271,8 +1189,7 @@ mod tests {
let network_config = generate(false, Some("cargo")).unwrap(); let network_config = generate(false, Some("cargo")).unwrap();
let mut spec = NetworkSpec::from_config(&network_config).await.unwrap(); let mut spec = NetworkSpec::from_config(&network_config).await.unwrap();
let node = spec.relaychain.nodes.first_mut().unwrap(); let node = spec.relaychain.nodes.first_mut().unwrap();
node.args node.args.push("--bootnodes {{ZOMBIE:bob:multiAddress')}}".into());
.push("--bootnodes {{ZOMBIE:bob:multiAddress')}}".into());
let (concurrency, limited) = calculate_concurrency(&spec).unwrap(); let (concurrency, limited) = calculate_concurrency(&spec).unwrap();
assert_eq!(concurrency, 1); assert_eq!(concurrency, 1);
assert!(limited); assert!(limited);
@@ -167,11 +167,8 @@ impl<T: FileSystem> Network<T> {
false, false,
)?; )?;
node_spec.available_args_output = Some( node_spec.available_args_output =
self.initial_spec Some(self.initial_spec.node_available_args_output(&node_spec, self.ns.clone()).await?);
.node_available_args_output(&node_spec, self.ns.clone())
.await?,
);
let base_dir = self.ns.base_dir().to_string_lossy(); let base_dir = self.ns.base_dir().to_string_lossy();
let scoped_fs = ScopedFilesystem::new(&self.filesystem, &base_dir); let scoped_fs = ScopedFilesystem::new(&self.filesystem, &base_dir);
@@ -208,8 +205,7 @@ impl<T: FileSystem> Network<T> {
// } // }
// Let's make sure node is up before adding // Let's make sure node is up before adding
node.wait_until_is_up(self.initial_spec.global_settings.network_spawn_timeout()) node.wait_until_is_up(self.initial_spec.global_settings.network_spawn_timeout()).await?;
.await?;
// Add node to relaychain data // Add node to relaychain data
self.add_running_node(node.clone(), None).await; self.add_running_node(node.clone(), None).await;
@@ -259,11 +255,8 @@ impl<T: FileSystem> Network<T> {
.iter() .iter()
.find(|para| para.id == para_id) .find(|para| para.id == para_id)
.ok_or(anyhow::anyhow!(format!("parachain: {para_id} not found!")))?; .ok_or(anyhow::anyhow!(format!("parachain: {para_id} not found!")))?;
let role = if spec.is_cumulus_based { let role =
ZombieRole::CumulusCollator if spec.is_cumulus_based { ZombieRole::CumulusCollator } else { ZombieRole::Collator };
} else {
ZombieRole::Collator
};
let chain_context = ChainDefaultContext { let chain_context = ChainDefaultContext {
default_command: spec.default_command.as_ref(), default_command: spec.default_command.as_ref(),
default_image: spec.default_image.as_ref(), default_image: spec.default_image.as_ref(),
@@ -339,17 +332,13 @@ impl<T: FileSystem> Network<T> {
spec.is_evm_based, spec.is_evm_based,
)?; )?;
node_spec.available_args_output = Some( node_spec.available_args_output =
self.initial_spec Some(self.initial_spec.node_available_args_output(&node_spec, self.ns.clone()).await?);
.node_available_args_output(&node_spec, self.ns.clone())
.await?,
);
let node = spawner::spawn_node(&node_spec, global_files_to_inject, &ctx).await?; let node = spawner::spawn_node(&node_spec, global_files_to_inject, &ctx).await?;
// Let's make sure node is up before adding // Let's make sure node is up before adding
node.wait_until_is_up(self.initial_spec.global_settings.network_spawn_timeout()) node.wait_until_is_up(self.initial_spec.global_settings.network_spawn_timeout()).await?;
.await?;
parachain.collators.push(node.clone()); parachain.collators.push(node.clone());
self.add_running_node(node, None).await; self.add_running_node(node, None).await;
@@ -366,12 +355,7 @@ impl<T: FileSystem> Network<T> {
.nodes_iter() .nodes_iter()
.map(|node| node.spec()) .map(|node| node.spec())
.flat_map(|spec| { .flat_map(|spec| {
[ [spec.ws_port.0, spec.rpc_port.0, spec.prometheus_port.0, spec.p2p_port.0]
spec.ws_port.0,
spec.rpc_port.0,
spec.prometheus_port.0,
spec.p2p_port.0,
]
}) })
.collect(); .collect();
@@ -384,11 +368,7 @@ impl<T: FileSystem> Network<T> {
.map(|(id, paras)| (*id, paras.len().saturating_sub(1) as u8)) .map(|(id, paras)| (*id, paras.len().saturating_sub(1) as u8))
.collect(); .collect();
let context = ValidationContext { let context = ValidationContext { used_ports, used_nodes_names, used_para_ids };
used_ports,
used_nodes_names,
used_para_ids,
};
let context = Rc::new(RefCell::new(context)); let context = Rc::new(RefCell::new(context));
ParachainConfigBuilder::new_with_running(context) ParachainConfigBuilder::new_with_running(context)
@@ -464,9 +444,8 @@ impl<T: FileSystem> Network<T> {
relay_chain_id.as_str().try_into()?, relay_chain_id.as_str().try_into()?,
)?; )?;
let chain_spec_raw_path = para_spec let chain_spec_raw_path =
.build_chain_spec(&relay_chain_id, &self.ns, &scoped_fs) para_spec.build_chain_spec(&relay_chain_id, &self.ns, &scoped_fs).await?;
.await?;
// Para artifacts // Para artifacts
let para_path_prefix = if let Some(custom_prefix) = custom_parchain_fs_prefix { let para_path_prefix = if let Some(custom_prefix) = custom_parchain_fs_prefix {
@@ -530,9 +509,7 @@ impl<T: FileSystem> Network<T> {
.relaychain() .relaychain()
.nodes .nodes
.first() .first()
.ok_or(anyhow::anyhow!( .ok_or(anyhow::anyhow!("At least one node of the relaychain should be running"))?
"At least one node of the relaychain should be running"
))?
.ws_uri(); .ws_uri();
if para_config.registration_strategy() == Some(&RegistrationStrategy::UsingExtrinsic) { if para_config.registration_strategy() == Some(&RegistrationStrategy::UsingExtrinsic) {
@@ -542,16 +519,12 @@ impl<T: FileSystem> Network<T> {
wasm_path: para_spec wasm_path: para_spec
.genesis_wasm .genesis_wasm
.artifact_path() .artifact_path()
.ok_or(anyhow::anyhow!( .ok_or(anyhow::anyhow!("artifact path for wasm must be set at this point",))?
"artifact path for wasm must be set at this point",
))?
.to_path_buf(), .to_path_buf(),
state_path: para_spec state_path: para_spec
.genesis_state .genesis_state
.artifact_path() .artifact_path()
.ok_or(anyhow::anyhow!( .ok_or(anyhow::anyhow!("artifact path for state must be set at this point",))?
"artifact path for state must be set at this point",
))?
.to_path_buf(), .to_path_buf(),
node_ws_url: first_node_url.to_string(), node_ws_url: first_node_url.to_string(),
onboard_as_para: para_spec.onboard_as_parachain, onboard_as_para: para_spec.onboard_as_parachain,
@@ -630,17 +603,13 @@ impl<T: FileSystem> Network<T> {
.parachains .parachains
.iter() .iter()
.find(|p| p.id == para_id) .find(|p| p.id == para_id)
.ok_or(anyhow::anyhow!( .ok_or(anyhow::anyhow!("no parachain with id = {para_id} available",))?;
"no parachain with id = {para_id} available",
))?;
let para_genesis_config = para.get_genesis_config()?; let para_genesis_config = para.get_genesis_config()?;
let first_node_url = self let first_node_url = self
.relaychain() .relaychain()
.nodes .nodes
.first() .first()
.ok_or(anyhow::anyhow!( .ok_or(anyhow::anyhow!("At least one node of the relaychain should be running"))?
"At least one node of the relaychain should be running"
))?
.ws_uri(); .ws_uri();
let register_para_options: RegisterParachainOptions = RegisterParachainOptions { let register_para_options: RegisterParachainOptions = RegisterParachainOptions {
id: para_id, id: para_id,
@@ -668,16 +637,9 @@ impl<T: FileSystem> Network<T> {
return Ok(node); return Ok(node);
} }
let list = self let list = self.nodes_iter().map(|n| &n.name).cloned().collect::<Vec<_>>().join(", ");
.nodes_iter()
.map(|n| &n.name)
.cloned()
.collect::<Vec<_>>()
.join(", ");
Err(anyhow::anyhow!( Err(anyhow::anyhow!("can't find node with name: {name:?}, should be one of {list}"))
"can't find node with name: {name:?}, should be one of {list}"
))
} }
pub fn get_node_mut( pub fn get_node_mut(
@@ -746,10 +708,7 @@ impl<T: FileSystem> Network<T> {
/// # Arguments /// # Arguments
/// * `unique_id` - unique id of the parachain /// * `unique_id` - unique id of the parachain
pub fn parachain_by_unique_id(&self, unique_id: impl AsRef<str>) -> Option<&Parachain> { pub fn parachain_by_unique_id(&self, unique_id: impl AsRef<str>) -> Option<&Parachain> {
self.parachains self.parachains.values().flat_map(|p| p.iter()).find(|p| p.unique_id == unique_id.as_ref())
.values()
.flat_map(|p| p.iter())
.find(|p| p.unique_id == unique_id.as_ref())
} }
pub fn parachains(&self) -> Vec<&Parachain> { pub fn parachains(&self) -> Vec<&Parachain> {
@@ -757,20 +716,15 @@ impl<T: FileSystem> Network<T> {
} }
pub(crate) fn nodes_iter(&self) -> impl Iterator<Item = &NetworkNode> { pub(crate) fn nodes_iter(&self) -> impl Iterator<Item = &NetworkNode> {
self.relay.nodes.iter().chain( self.relay
self.parachains .nodes
.values() .iter()
.flat_map(|p| p.iter()) .chain(self.parachains.values().flat_map(|p| p.iter()).flat_map(|p| &p.collators))
.flat_map(|p| &p.collators),
)
} }
pub(crate) fn nodes_iter_mut(&mut self) -> impl Iterator<Item = &mut NetworkNode> { pub(crate) fn nodes_iter_mut(&mut self) -> impl Iterator<Item = &mut NetworkNode> {
self.relay.nodes.iter_mut().chain( self.relay.nodes.iter_mut().chain(
self.parachains self.parachains.values_mut().flat_map(|p| p.iter_mut()).flat_map(|p| &mut p.collators),
.values_mut()
.flat_map(|p| p.iter_mut())
.flat_map(|p| &mut p.collators),
) )
} }
@@ -784,9 +738,7 @@ impl<T: FileSystem> Network<T> {
/// * `Ok()` if the node is up before timeout occured. /// * `Ok()` if the node is up before timeout occured.
/// * `Err(e)` if timeout or other error occurred while waiting. /// * `Err(e)` if timeout or other error occurred while waiting.
pub async fn wait_until_is_up(&self, timeout_secs: u64) -> Result<(), anyhow::Error> { pub async fn wait_until_is_up(&self, timeout_secs: u64) -> Result<(), anyhow::Error> {
let handles = self let handles = self.nodes_iter().map(|node| node.wait_until_is_up(timeout_secs));
.nodes_iter()
.map(|node| node.wait_until_is_up(timeout_secs));
futures::future::try_join_all(handles).await?; futures::future::try_join_all(handles).await?;
@@ -104,11 +104,7 @@ impl LogLineCountOptions {
timeout: Duration, timeout: Duration,
wait_until_timeout_elapses: bool, wait_until_timeout_elapses: bool,
) -> Self { ) -> Self {
Self { Self { predicate: Arc::new(predicate), timeout, wait_until_timeout_elapses }
predicate: Arc::new(predicate),
timeout,
wait_until_timeout_elapses,
}
} }
pub fn no_occurences_within_timeout(timeout: Duration) -> Self { pub fn no_occurences_within_timeout(timeout: Duration) -> Self {
@@ -220,9 +216,7 @@ impl NetworkNode {
.await .await
.map_err(|e| anyhow!("Error awaiting http_client to ws be ready, err: {e}"))?; .map_err(|e| anyhow!("Error awaiting http_client to ws be ready, err: {e}"))?;
self.try_client() self.try_client().await.map_err(|e| anyhow!("Can't create a subxt client, err: {e}"))
.await
.map_err(|e| anyhow!("Can't create a subxt client, err: {e}"))
} }
/// Wait until get the [online client](subxt::client::OnlineClient) for the node with a defined timeout /// Wait until get the [online client](subxt::client::OnlineClient) for the node with a defined timeout
@@ -231,10 +225,7 @@ impl NetworkNode {
timeout_secs: impl Into<u64>, timeout_secs: impl Into<u64>,
) -> Result<OnlineClient<Config>, anyhow::Error> { ) -> Result<OnlineClient<Config>, anyhow::Error> {
debug!("waiting until subxt client is ready"); debug!("waiting until subxt client is ready");
tokio::time::timeout( tokio::time::timeout(Duration::from_secs(timeout_secs.into()), self.wait_client::<Config>())
Duration::from_secs(timeout_secs.into()),
self.wait_client::<Config>(),
)
.await? .await?
} }
@@ -386,9 +377,7 @@ impl NetworkNode {
} }
} else { } else {
// timeout // timeout
Err(anyhow!( Err(anyhow!("Timeout ({secs}), waiting for metric {metric_name} pass the predicate"))
"Timeout ({secs}), waiting for metric {metric_name} pass the predicate"
))
} }
} }
@@ -485,10 +474,7 @@ impl NetworkNode {
options: LogLineCountOptions, options: LogLineCountOptions,
) -> Result<LogLineCount, anyhow::Error> { ) -> Result<LogLineCount, anyhow::Error> {
let substring = substring.into(); let substring = substring.into();
debug!( debug!("waiting until match lines count within {} seconds", options.timeout.as_secs_f64());
"waiting until match lines count within {} seconds",
options.timeout.as_secs_f64()
);
let start = tokio::time::Instant::now(); let start = tokio::time::Instant::now();
@@ -626,16 +612,11 @@ mod tests {
impl MockNode { impl MockNode {
fn new() -> Self { fn new() -> Self {
Self { Self { logs: Arc::new(Mutex::new(vec![])) }
logs: Arc::new(Mutex::new(vec![])),
}
} }
fn logs_push(&self, lines: Vec<impl Into<String>>) { fn logs_push(&self, lines: Vec<impl Into<String>>) {
self.logs self.logs.lock().unwrap().extend(lines.into_iter().map(|l| l.into()));
.lock()
.unwrap()
.extend(lines.into_iter().map(|l| l.into()));
} }
} }
@@ -763,9 +744,8 @@ mod tests {
wait_until_timeout_elapses: false, wait_until_timeout_elapses: false,
}; };
let log_line_count = mock_node let log_line_count =
.wait_log_line_count_with_timeout("system ready", false, options) mock_node.wait_log_line_count_with_timeout("system ready", false, options).await?;
.await?;
assert!(matches!(log_line_count, LogLineCount::TargetReached(1))); assert!(matches!(log_line_count, LogLineCount::TargetReached(1)));
@@ -844,9 +824,8 @@ mod tests {
wait_until_timeout_elapses: false, wait_until_timeout_elapses: false,
}; };
let log_line_count = mock_node let log_line_count =
.wait_log_line_count_with_timeout("system ready", false, options) mock_node.wait_log_line_count_with_timeout("system ready", false, options).await?;
.await?;
assert!(matches!(log_line_count, LogLineCount::TargetFailed(1))); assert!(matches!(log_line_count, LogLineCount::TargetFailed(1)));
@@ -31,11 +31,7 @@ impl ChainUpgrade for Relaychain {
async fn runtime_upgrade(&self, options: RuntimeUpgradeOptions) -> Result<(), anyhow::Error> { async fn runtime_upgrade(&self, options: RuntimeUpgradeOptions) -> Result<(), anyhow::Error> {
// check if the node is valid first // check if the node is valid first
let node = if let Some(node_name) = &options.node_name { let node = if let Some(node_name) = &options.node_name {
if let Some(node) = self if let Some(node) = self.nodes().into_iter().find(|node| node.name() == node_name) {
.nodes()
.into_iter()
.find(|node| node.name() == node_name)
{
node node
} else { } else {
return Err(anyhow!("Node: {node_name} is not part of the set of nodes")); return Err(anyhow!("Node: {node_name} is not part of the set of nodes"));
@@ -55,12 +51,7 @@ impl ChainUpgrade for Relaychain {
impl Relaychain { impl Relaychain {
pub(crate) fn new(chain: String, chain_id: String, chain_spec_path: PathBuf) -> Self { pub(crate) fn new(chain: String, chain_id: String, chain_spec_path: PathBuf) -> Self {
Self { Self { chain, chain_id, chain_spec_path, nodes: Default::default() }
chain,
chain_id,
chain_spec_path,
nodes: Default::default(),
}
} }
// Public API // Public API
@@ -48,11 +48,7 @@ impl ChainUpgrade for Parachain {
async fn runtime_upgrade(&self, options: RuntimeUpgradeOptions) -> Result<(), anyhow::Error> { async fn runtime_upgrade(&self, options: RuntimeUpgradeOptions) -> Result<(), anyhow::Error> {
// check if the node is valid first // check if the node is valid first
let node = if let Some(node_name) = &options.node_name { let node = if let Some(node_name) = &options.node_name {
if let Some(node) = self if let Some(node) = self.collators().into_iter().find(|node| node.name() == node_name) {
.collators()
.into_iter()
.find(|node| node.name() == node_name)
{
node node
} else { } else {
return Err(anyhow!("Node: {node_name} is not part of the set of nodes")); return Err(anyhow!("Node: {node_name} is not part of the set of nodes"));
@@ -159,23 +155,14 @@ impl Parachain {
let genesis_state = scoped_fs let genesis_state = scoped_fs
.read_to_string(options.state_path) .read_to_string(options.state_path)
.await .await
.expect(&format!( .expect(&format!("State Path should be ok by this point {THIS_IS_A_BUG}"));
"State Path should be ok by this point {THIS_IS_A_BUG}"
));
let wasm_data = scoped_fs let wasm_data = scoped_fs
.read_to_string(options.wasm_path) .read_to_string(options.wasm_path)
.await .await
.expect(&format!( .expect(&format!("Wasm Path should be ok by this point {THIS_IS_A_BUG}"));
"Wasm Path should be ok by this point {THIS_IS_A_BUG}"
));
wait_ws_ready(options.node_ws_url.as_str()) wait_ws_ready(options.node_ws_url.as_str()).await.map_err(|_| {
.await anyhow::anyhow!("Error waiting for ws to be ready, at {}", options.node_ws_url.as_str())
.map_err(|_| {
anyhow::anyhow!(
"Error waiting for ws to be ready, at {}",
options.node_ws_url.as_str()
)
})?; })?;
let api: OnlineClient<BizinikiwConfig> = get_client_from_url(&options.node_ws_url).await?; let api: OnlineClient<BizinikiwConfig> = get_client_from_url(&options.node_ws_url).await?;
@@ -186,14 +173,8 @@ impl Parachain {
vec![ vec![
Value::primitive(options.id.into()), Value::primitive(options.id.into()),
Value::named_composite([ Value::named_composite([
( ("genesis_head", Value::from_bytes(hex::decode(&genesis_state[2..])?)),
"genesis_head", ("validation_code", Value::from_bytes(hex::decode(&wasm_data[2..])?)),
Value::from_bytes(hex::decode(&genesis_state[2..])?),
),
(
"validation_code",
Value::from_bytes(hex::decode(&wasm_data[2..])?),
),
("para_kind", Value::bool(options.onboard_as_para)), ("para_kind", Value::bool(options.onboard_as_para)),
]), ]),
], ],
@@ -204,10 +185,7 @@ impl Parachain {
// TODO: uncomment below and fix the sign and submit (and follow afterwards until // TODO: uncomment below and fix the sign and submit (and follow afterwards until
// finalized block) to register the parachain // finalized block) to register the parachain
let mut tx = api let mut tx = api.tx().sign_and_submit_then_watch_default(&sudo_call, &sudo).await?;
.tx()
.sign_and_submit_then_watch_default(&sudo_call, &sudo)
.await?;
// Below we use the low level API to replicate the `wait_for_in_block` behaviour // Below we use the low level API to replicate the `wait_for_in_block` behaviour
// which was removed in subxt 0.33.0. See https://github.com/paritytech/subxt/pull/1237. // which was removed in subxt 0.33.0. See https://github.com/paritytech/subxt/pull/1237.
@@ -274,10 +252,7 @@ mod tests {
assert_eq!(para.unique_id, "100"); assert_eq!(para.unique_id, "100");
assert_eq!(para.chain_id, Some("rococo-local".to_string())); assert_eq!(para.chain_id, Some("rococo-local".to_string()));
assert_eq!(para.chain, None); assert_eq!(para.chain, None);
assert_eq!( assert_eq!(para.chain_spec_path, Some(PathBuf::from("/tmp/rococo-local.json")));
para.chain_spec_path,
Some(PathBuf::from("/tmp/rococo-local.json"))
);
} }
#[tokio::test] #[tokio::test]
@@ -300,18 +275,11 @@ mod tests {
let para_spec = let para_spec =
TeyrchainSpec::from_config(&para_config, "rococo-local".try_into().unwrap()).unwrap(); TeyrchainSpec::from_config(&para_config, "rococo-local".try_into().unwrap()).unwrap();
let fs = support::fs::in_memory::InMemoryFileSystem::new(HashMap::default()); let fs = support::fs::in_memory::InMemoryFileSystem::new(HashMap::default());
let scoped_fs = ScopedFilesystem { let scoped_fs = ScopedFilesystem { fs: &fs, base_dir: "/tmp/some" };
fs: &fs,
base_dir: "/tmp/some",
};
let files = vec![TransferedFile::new( let files =
PathBuf::from("/tmp/some"), vec![TransferedFile::new(PathBuf::from("/tmp/some"), PathBuf::from("/tmp/some"))];
PathBuf::from("/tmp/some"), let para = Parachain::from_spec(&para_spec, &files, &scoped_fs).await.unwrap();
)];
let para = Parachain::from_spec(&para_spec, &files, &scoped_fs)
.await
.unwrap();
println!("{para:#?}"); println!("{para:#?}");
assert_eq!(para.para_id, 100); assert_eq!(para.para_id, 100);
assert_eq!(para.unique_id, "100"); assert_eq!(para.unique_id, "100");
@@ -320,10 +288,7 @@ mod tests {
// one file should be added. // one file should be added.
assert_eq!(para.files_to_inject.len(), 1); assert_eq!(para.files_to_inject.len(), 1);
assert_eq!( assert_eq!(
para.bootnodes_addresses() para.bootnodes_addresses().iter().map(|addr| addr.to_string()).collect::<Vec<_>>(),
.iter()
.map(|addr| addr.to_string())
.collect::<Vec<_>>(),
bootnode_addresses bootnode_addresses
); );
} }
@@ -18,9 +18,7 @@ pub struct Metrics {
impl Metrics { impl Metrics {
fn new(endpoint: impl Into<Url>) -> Self { fn new(endpoint: impl Into<Url>) -> Self {
Self { Self { endpoint: endpoint.into() }
endpoint: endpoint.into(),
}
} }
async fn fetch_metrics( async fn fetch_metrics(
@@ -53,19 +53,12 @@ impl NetworkSpec {
Ok(NetworkSpec { Ok(NetworkSpec {
relaychain, relaychain,
parachains, parachains,
hrmp_channels: network_config hrmp_channels: network_config.hrmp_channels().into_iter().cloned().collect(),
.hrmp_channels()
.into_iter()
.cloned()
.collect(),
global_settings: network_config.global_settings().clone(), global_settings: network_config.global_settings().clone(),
}) })
} else { } else {
let errs_str = errs let errs_str =
.into_iter() errs.into_iter().map(|e| e.to_string()).collect::<Vec<String>>().join("\n");
.map(|e| e.to_string())
.collect::<Vec<String>>()
.join("\n");
Err(OrchestratorError::InvalidConfig(errs_str)) Err(OrchestratorError::InvalidConfig(errs_str))
} }
} }
@@ -107,24 +100,18 @@ impl NetworkSpec {
let node = if let Some(node) = node { let node = if let Some(node) = node {
Some(node) Some(node)
} else { } else {
let node = self let node = self.parachains.iter().find_map(|para| para.collators.iter().find(cmp_fn));
.parachains
.iter()
.find_map(|para| para.collators.iter().find(cmp_fn));
node node
}; };
let output = if let Some(node) = node { let output = if let Some(node) = node {
node.available_args_output.clone().expect(&format!( node.available_args_output
"args_output should be set for running nodes {THIS_IS_A_BUG}" .clone()
)) .expect(&format!("args_output should be set for running nodes {THIS_IS_A_BUG}"))
} else { } else {
// we need to compute the args output // we need to compute the args output
let image = node_spec let image = node_spec.image.as_ref().map(|image| image.as_str().to_string());
.image
.as_ref()
.map(|image| image.as_str().to_string());
let command = node_spec.command.as_str().to_string(); let command = node_spec.command.as_str().to_string();
ns.get_node_available_args((command, image)).await? ns.get_node_available_args((command, image)).await?
@@ -201,10 +188,7 @@ impl NetworkSpec {
fn collect_network_nodes(&mut self) -> Vec<&mut NodeSpec> { fn collect_network_nodes(&mut self) -> Vec<&mut NodeSpec> {
vec![ vec![
self.relaychain.nodes.iter_mut().collect::<Vec<_>>(), self.relaychain.nodes.iter_mut().collect::<Vec<_>>(),
self.parachains self.parachains.iter_mut().flat_map(|para| para.collators.iter_mut()).collect(),
.iter_mut()
.flat_map(|para| para.collators.iter_mut())
.collect(),
] ]
.into_iter() .into_iter()
.flatten() .flatten()
@@ -223,10 +207,7 @@ impl NetworkSpec {
.image .image
.as_ref() .as_ref()
.map(|image| { .map(|image| {
( (Some(image.as_str().to_string()), node.command.as_str().to_string())
Some(image.as_str().to_string()),
node.command.as_str().to_string(),
)
}) })
.unwrap_or_else(|| (None, node.command.as_str().to_string())); .unwrap_or_else(|| (None, node.command.as_str().to_string()));
@@ -255,9 +236,8 @@ impl NetworkSpec {
let command = command.clone(); let command = command.clone();
async move { async move {
// get node available args output from image/command // get node available args output from image/command
let available_args = ns let available_args =
.get_node_available_args((command.clone(), image.clone())) ns.get_node_available_args((command.clone(), image.clone())).await?;
.await?;
debug!( debug!(
"retrieved available args for image: {:?}, command: {}", "retrieved available args for image: {:?}, command: {}",
image, command image, command
@@ -279,9 +259,7 @@ impl NetworkSpec {
for (image, command, available_args_output) in available_args_outputs { for (image, command, available_args_output) in available_args_outputs {
let nodes = image_command_to_nodes_mapping let nodes = image_command_to_nodes_mapping
.get_mut(&(image, command)) .get_mut(&(image, command))
.expect(&format!( .expect(&format!("node image/command key should exist {THIS_IS_A_BUG}"));
"node image/command key should exist {THIS_IS_A_BUG}"
));
for node in nodes { for node in nodes {
node.available_args_output = Some(available_args_output.clone()); node.available_args_output = Some(available_args_output.clone());
@@ -162,11 +162,7 @@ impl NodeSpec {
// If `args` is set at `node` level use them // If `args` is set at `node` level use them
// otherwise use the default_args (can be empty). // otherwise use the default_args (can be empty).
let args: Vec<Arg> = if node_config.args().is_empty() { let args: Vec<Arg> = if node_config.args().is_empty() {
chain_context chain_context.default_args.iter().map(|x| x.to_owned().clone()).collect()
.default_args
.iter()
.map(|x| x.to_owned().clone())
.collect()
} else { } else {
node_config.args().into_iter().cloned().collect() node_config.args().into_iter().cloned().collect()
}; };
@@ -180,9 +176,7 @@ impl NodeSpec {
if evm_based { if evm_based {
if let Some(session_key) = node_config.override_eth_key() { if let Some(session_key) = node_config.override_eth_key() {
accounts accounts.accounts.insert("eth".into(), NodeAccount::new(session_key, session_key));
.accounts
.insert("eth".into(), NodeAccount::new(session_key, session_key));
} }
} }
@@ -215,11 +209,7 @@ impl NodeSpec {
is_bootnode: node_config.is_bootnode(), is_bootnode: node_config.is_bootnode(),
initial_balance: node_config.initial_balance(), initial_balance: node_config.initial_balance(),
env: node_config.env().into_iter().cloned().collect(), env: node_config.env().into_iter().cloned().collect(),
bootnodes_addresses: node_config bootnodes_addresses: node_config.bootnodes_addresses().into_iter().cloned().collect(),
.bootnodes_addresses()
.into_iter()
.cloned()
.collect(),
resources: node_config.resources().cloned(), resources: node_config.resources().cloned(),
p2p_cert_hash: node_config.p2p_cert_hash().map(str::to_string), p2p_cert_hash: node_config.p2p_cert_hash().map(str::to_string),
db_snapshot: db_snapshot.cloned(), db_snapshot: db_snapshot.cloned(),
@@ -261,10 +251,7 @@ impl NodeSpec {
} else if let Some(cmd) = chain_context.default_command { } else if let Some(cmd) = chain_context.default_command {
cmd.clone() cmd.clone()
} else { } else {
return Err(OrchestratorError::InvalidNodeConfig( return Err(OrchestratorError::InvalidNodeConfig(name, "command".to_string()));
name,
"command".to_string(),
));
}; };
let subcommand = options.subcommand.clone(); let subcommand = options.subcommand.clone();
@@ -272,11 +259,7 @@ impl NodeSpec {
// If `args` is set at `node` level use them // If `args` is set at `node` level use them
// otherwise use the default_args (can be empty). // otherwise use the default_args (can be empty).
let args: Vec<Arg> = if options.args.is_empty() { let args: Vec<Arg> = if options.args.is_empty() {
chain_context chain_context.default_args.iter().map(|x| x.to_owned().clone()).collect()
.default_args
.iter()
.map(|x| x.to_owned().clone())
.collect()
} else { } else {
options.args options.args
}; };
@@ -284,18 +267,13 @@ impl NodeSpec {
let (key, peer_id) = generators::generate_node_identity(&name)?; let (key, peer_id) = generators::generate_node_identity(&name)?;
let mut name_capitalized = name.clone(); let mut name_capitalized = name.clone();
let seed = format!( let seed = format!("//{}{name_capitalized}", name_capitalized.remove(0).to_uppercase());
"//{}{name_capitalized}",
name_capitalized.remove(0).to_uppercase()
);
let accounts = generators::generate_node_keys(&seed)?; let accounts = generators::generate_node_keys(&seed)?;
let mut accounts = NodeAccounts { seed, accounts }; let mut accounts = NodeAccounts { seed, accounts };
if evm_based { if evm_based {
if let Some(session_key) = options.override_eth_key.as_ref() { if let Some(session_key) = options.override_eth_key.as_ref() {
accounts accounts.accounts.insert("eth".into(), NodeAccount::new(session_key, session_key));
.accounts
.insert("eth".into(), NodeAccount::new(session_key, session_key));
} }
} }
@@ -344,9 +322,7 @@ impl NodeSpec {
pub(crate) fn supports_arg(&self, arg: impl AsRef<str>) -> bool { pub(crate) fn supports_arg(&self, arg: impl AsRef<str>) -> bool {
self.available_args_output self.available_args_output
.as_ref() .as_ref()
.expect(&format!( .expect(&format!("available args should be present at this point {THIS_IS_A_BUG}"))
"available args should be present at this point {THIS_IS_A_BUG}"
))
.contains(arg.as_ref()) .contains(arg.as_ref())
} }
@@ -121,20 +121,14 @@ impl TeyrchainSpec {
let chain_spec = if config.is_cumulus_based() { let chain_spec = if config.is_cumulus_based() {
// we need a chain-spec // we need a chain-spec
let chain_name = if let Some(chain_name) = config.chain() { let chain_name =
chain_name.as_str() if let Some(chain_name) = config.chain() { chain_name.as_str() } else { "" };
} else {
""
};
let chain_spec_builder = if chain_name.is_empty() { let chain_spec_builder = if chain_name.is_empty() {
// if the chain don't have name use the unique_id for the name of the file // if the chain don't have name use the unique_id for the name of the file
ChainSpec::new( ChainSpec::new(
config.unique_id().to_string(), config.unique_id().to_string(),
Context::Para { Context::Para { relay_chain, para_id: config.id() },
relay_chain,
para_id: config.id(),
},
) )
} else { } else {
let chain_spec_file_name = if config.unique_id().contains('-') { let chain_spec_file_name = if config.unique_id().contains('-') {
@@ -144,10 +138,7 @@ impl TeyrchainSpec {
}; };
ChainSpec::new( ChainSpec::new(
chain_spec_file_name, chain_spec_file_name,
Context::Para { Context::Para { relay_chain, para_id: config.id() },
relay_chain,
para_id: config.id(),
},
) )
}; };
let chain_spec_builder = chain_spec_builder.set_chain_name(chain_name); let chain_spec_builder = chain_spec_builder.set_chain_name(chain_name);
@@ -226,11 +217,8 @@ impl TeyrchainSpec {
ParaArtifactBuildOption::Path(path.to_string()), ParaArtifactBuildOption::Path(path.to_string()),
) )
} else { } else {
let cmd = if let Some(cmd) = config.genesis_state_generator() { let cmd =
cmd.cmd() if let Some(cmd) = config.genesis_state_generator() { cmd.cmd() } else { main_cmd };
} else {
main_cmd
};
ParaArtifact::new( ParaArtifact::new(
ParaArtifactType::State, ParaArtifactType::State,
ParaArtifactBuildOption::Command(cmd.as_str().into()), ParaArtifactBuildOption::Command(cmd.as_str().into()),
@@ -249,10 +237,7 @@ impl TeyrchainSpec {
} else { } else {
main_cmd.as_str() main_cmd.as_str()
}; };
ParaArtifact::new( ParaArtifact::new(ParaArtifactType::Wasm, ParaArtifactBuildOption::Command(cmd.into()))
ParaArtifactType::Wasm,
ParaArtifactBuildOption::Command(cmd.into()),
)
.image(main_image.clone()) .image(main_image.clone())
}; };
@@ -344,13 +329,9 @@ impl TeyrchainSpec {
chain_spec.build(ns, scoped_fs).await?; chain_spec.build(ns, scoped_fs).await?;
debug!("parachain chain-spec built!"); debug!("parachain chain-spec built!");
chain_spec chain_spec.customize_para(&cloned, relay_chain_id, scoped_fs).await?;
.customize_para(&cloned, relay_chain_id, scoped_fs)
.await?;
debug!("parachain chain-spec customized!"); debug!("parachain chain-spec customized!");
chain_spec chain_spec.build_raw(ns, scoped_fs, Some(relay_chain_id.try_into()?)).await?;
.build_raw(ns, scoped_fs, Some(relay_chain_id.try_into()?))
.await?;
debug!("parachain chain-spec raw built!"); debug!("parachain chain-spec raw built!");
// override wasm if needed // override wasm if needed
@@ -360,17 +341,12 @@ impl TeyrchainSpec {
// override raw spec if needed // override raw spec if needed
if let Some(ref raw_spec_override) = self.raw_spec_override { if let Some(ref raw_spec_override) = self.raw_spec_override {
chain_spec chain_spec.override_raw_spec(scoped_fs, raw_spec_override).await?;
.override_raw_spec(scoped_fs, raw_spec_override)
.await?;
} }
let chain_spec_raw_path = let chain_spec_raw_path = chain_spec.raw_path().ok_or(
chain_spec OrchestratorError::InvariantError("chain-spec raw path should be set now"),
.raw_path() )?;
.ok_or(OrchestratorError::InvariantError(
"chain-spec raw path should be set now",
))?;
Some(chain_spec_raw_path.to_path_buf()) Some(chain_spec_raw_path.to_path_buf())
} else { } else {
@@ -21,10 +21,7 @@ pub struct NodeAccount {
impl NodeAccount { impl NodeAccount {
pub fn new(addr: impl Into<String>, pk: impl Into<String>) -> Self { pub fn new(addr: impl Into<String>, pk: impl Into<String>) -> Self {
Self { Self { address: addr.into(), public_key: pk.into() }
address: addr.into(),
public_key: pk.into(),
}
} }
} }
@@ -35,10 +32,7 @@ pub struct NodeAccounts {
} }
#[derive(Clone, Default, Debug, Serialize, Deserialize)] #[derive(Clone, Default, Debug, Serialize, Deserialize)]
pub struct ParkedPort( pub struct ParkedPort(pub(crate) Port, #[serde(skip)] pub(crate) Arc<RwLock<Option<TcpListener>>>);
pub(crate) Port,
#[serde(skip)] pub(crate) Arc<RwLock<Option<TcpListener>>>,
);
impl ParkedPort { impl ParkedPort {
pub(crate) fn new(port: u16, listener: TcpListener) -> ParkedPort { pub(crate) fn new(port: u16, listener: TcpListener) -> ParkedPort {
@@ -84,11 +78,7 @@ pub struct RuntimeUpgradeOptions {
impl RuntimeUpgradeOptions { impl RuntimeUpgradeOptions {
pub fn new(wasm: AssetLocation) -> Self { pub fn new(wasm: AssetLocation) -> Self {
Self { Self { wasm, node_name: None, seed: None }
wasm,
node_name: None,
seed: None,
}
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -63,15 +63,10 @@ where
// (parachain_id) should be set then. // (parachain_id) should be set then.
if node.is_validator && (ctx.parachain.is_none() || ctx.parachain_id.is_some()) { if node.is_validator && (ctx.parachain.is_none() || ctx.parachain_id.is_some()) {
// Generate keystore for node // Generate keystore for node
let node_files_path = if let Some(para) = ctx.parachain { let node_files_path =
para.id.to_string() if let Some(para) = ctx.parachain { para.id.to_string() } else { node.name.clone() };
} else { let asset_hub_polkadot =
node.name.clone() ctx.parachain_id.map(|id| id.starts_with("asset-hub-polkadot")).unwrap_or_default();
};
let asset_hub_polkadot = ctx
.parachain_id
.map(|id| id.starts_with("asset-hub-polkadot"))
.unwrap_or_default();
let keystore_key_types = node.keystore_key_types.iter().map(String::as_str).collect(); let keystore_key_types = node.keystore_key_types.iter().map(String::as_str).collect();
let key_filenames = generators::generate_node_keystore( let key_filenames = generators::generate_node_keystore(
&node.accounts, &node.accounts,
@@ -85,15 +80,13 @@ where
// Paths returned are relative to the base dir, we need to convert into // Paths returned are relative to the base dir, we need to convert into
// fullpaths to inject them in the nodes. // fullpaths to inject them in the nodes.
let remote_keystore_chain_id = if let Some(id) = ctx.parachain_id { let remote_keystore_chain_id =
id if let Some(id) = ctx.parachain_id { id } else { ctx.chain_id };
} else {
ctx.chain_id
};
let keystore_path = node.keystore_path.clone().unwrap_or(PathBuf::from(format!( let keystore_path = node
"/data/chains/{remote_keystore_chain_id}/keystore", .keystore_path
))); .clone()
.unwrap_or(PathBuf::from(format!("/data/chains/{remote_keystore_chain_id}/keystore",)));
for key_filename in key_filenames { for key_filename in key_filenames {
let f = TransferedFile::new( let f = TransferedFile::new(
@@ -113,11 +106,7 @@ where
let base_dir = format!("{}/{}", ctx.ns.base_dir().to_string_lossy(), &node.name); let base_dir = format!("{}/{}", ctx.ns.base_dir().to_string_lossy(), &node.name);
let (cfg_path, data_path, relay_data_path) = if !ctx.ns.capabilities().prefix_with_full_path { let (cfg_path, data_path, relay_data_path) = if !ctx.ns.capabilities().prefix_with_full_path {
( (NODE_CONFIG_DIR.into(), NODE_DATA_DIR.into(), NODE_RELAY_DATA_DIR.into())
NODE_CONFIG_DIR.into(),
NODE_DATA_DIR.into(),
NODE_RELAY_DATA_DIR.into(),
)
} else { } else {
let cfg_path = format!("{}{NODE_CONFIG_DIR}", &base_dir); let cfg_path = format!("{}{NODE_CONFIG_DIR}", &base_dir);
let data_path = format!("{}{NODE_DATA_DIR}", &base_dir); let data_path = format!("{}{NODE_DATA_DIR}", &base_dir);
@@ -148,9 +137,9 @@ where
generators::generate_node_command(node, gen_opts, maybe_para_id) generators::generate_node_command(node, gen_opts, maybe_para_id)
}, },
ZombieRole::CumulusCollator => { ZombieRole::CumulusCollator => {
let para = ctx.parachain.expect(&format!( let para = ctx
"parachain must be part of the context {THIS_IS_A_BUG}" .parachain
)); .expect(&format!("parachain must be part of the context {THIS_IS_A_BUG}"));
collator_full_node_prom_port = node.full_node_prometheus_port.as_ref().map(|p| p.0); collator_full_node_prom_port = node.full_node_prometheus_port.as_ref().map(|p| p.0);
generators::generate_node_command_cumulus(node, gen_opts, para.id) generators::generate_node_command_cumulus(node, gen_opts, para.id)
@@ -166,12 +155,7 @@ where
.map(|arg| apply_running_network_replacements(arg, &ctx.nodes_by_name)) .map(|arg| apply_running_network_replacements(arg, &ctx.nodes_by_name))
.collect(); .collect();
info!( info!("🚀 {}, spawning.... with command: {} {}", node.name, program, args.join(" "));
"🚀 {}, spawning.... with command: {} {}",
node.name,
program,
args.join(" ")
);
let ports = if ctx.ns.capabilities().use_default_ports_in_cmd { let ports = if ctx.ns.capabilities().use_default_ports_in_cmd {
// should use default ports to as internal // should use default ports to as internal
@@ -181,20 +165,12 @@ where
(PROMETHEUS_PORT, node.prometheus_port.0), (PROMETHEUS_PORT, node.prometheus_port.0),
] ]
} else { } else {
[ [(P2P_PORT, P2P_PORT), (RPC_PORT, RPC_PORT), (PROMETHEUS_PORT, PROMETHEUS_PORT)]
(P2P_PORT, P2P_PORT),
(RPC_PORT, RPC_PORT),
(PROMETHEUS_PORT, PROMETHEUS_PORT),
]
}; };
let spawn_ops = SpawnNodeOptions::new(node.name.clone(), program) let spawn_ops = SpawnNodeOptions::new(node.name.clone(), program)
.args(args) .args(args)
.env( .env(node.env.iter().map(|var| (var.name.clone(), var.value.clone())))
node.env
.iter()
.map(|var| (var.name.clone(), var.value.clone())),
)
.injected_files(files_to_inject) .injected_files(files_to_inject)
.created_paths(created_paths) .created_paths(created_paths)
.db_snapshot(node.db_snapshot.clone()) .db_snapshot(node.db_snapshot.clone())
@@ -220,17 +196,11 @@ where
} }
let running_node = ctx.ns.spawn_node(&spawn_ops).await.with_context(|| { let running_node = ctx.ns.spawn_node(&spawn_ops).await.with_context(|| {
format!( format!("Failed to spawn node: {} with opts: {:#?}", node.name, spawn_ops)
"Failed to spawn node: {} with opts: {:#?}",
node.name, spawn_ops
)
})?; })?;
let mut ip_to_use = if let Some(local_ip) = ctx.global_settings.local_ip() { let mut ip_to_use =
*local_ip if let Some(local_ip) = ctx.global_settings.local_ip() { *local_ip } else { LOCALHOST };
} else {
LOCALHOST
};
let (rpc_port_external, prometheus_port_external, p2p_external); let (rpc_port_external, prometheus_port_external, p2p_external);
@@ -20,15 +20,11 @@ impl<Config: pezkuwi_subxt::Config + Send + Sync> ClientFromUrl for OnlineClient
#[async_trait::async_trait] #[async_trait::async_trait]
impl ClientFromUrl for RpcClient { impl ClientFromUrl for RpcClient {
async fn from_secure_url(url: &str) -> Result<Self, pezkuwi_subxt::Error> { async fn from_secure_url(url: &str) -> Result<Self, pezkuwi_subxt::Error> {
Self::from_url(url) Self::from_url(url).await.map_err(pezkuwi_subxt::Error::from)
.await
.map_err(pezkuwi_subxt::Error::from)
} }
async fn from_insecure_url(url: &str) -> Result<Self, pezkuwi_subxt::Error> { async fn from_insecure_url(url: &str) -> Result<Self, pezkuwi_subxt::Error> {
Self::from_insecure_url(url) Self::from_insecure_url(url).await.map_err(pezkuwi_subxt::Error::from)
.await
.map_err(pezkuwi_subxt::Error::from)
} }
} }
@@ -9,10 +9,7 @@ pub async fn upgrade(
wasm_data: &[u8], wasm_data: &[u8],
sudo: &Keypair, sudo: &Keypair,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
debug!( debug!("Upgrading runtime, using node: {} with endpoting {}", node.name, node.ws_uri);
"Upgrading runtime, using node: {} with endpoting {}",
node.name, node.ws_uri
);
let api: OnlineClient<BizinikiwConfig> = node.wait_client().await?; let api: OnlineClient<BizinikiwConfig> = node.wait_client().await?;
let upgrade = pezkuwi_subxt::dynamic::tx( let upgrade = pezkuwi_subxt::dynamic::tx(
@@ -33,10 +30,7 @@ pub async fn upgrade(
], ],
); );
let mut tx = api let mut tx = api.tx().sign_and_submit_then_watch_default(&sudo_call, sudo).await?;
.tx()
.sign_and_submit_then_watch_default(&sudo_call, sudo)
.await?;
// Below we use the low level API to replicate the `wait_for_in_block` behaviour // Below we use the low level API to replicate the `wait_for_in_block` behaviour
// which was removed in subxt 0.33.0. See https://github.com/paritytech/subxt/pull/1237. // which was removed in subxt 0.33.0. See https://github.com/paritytech/subxt/pull/1237.
@@ -45,16 +39,9 @@ pub async fn upgrade(
match &status { match &status {
TxStatus::InBestBlock(tx_in_block) | TxStatus::InFinalizedBlock(tx_in_block) => { TxStatus::InBestBlock(tx_in_block) | TxStatus::InFinalizedBlock(tx_in_block) => {
let _result = tx_in_block.wait_for_success().await?; let _result = tx_in_block.wait_for_success().await?;
let block_status = if status.as_finalized().is_some() { let block_status =
"Finalized" if status.as_finalized().is_some() { "Finalized" } else { "Best" };
} else { info!("[{}] In block: {:#?}", block_status, tx_in_block.block_hash());
"Best"
};
info!(
"[{}] In block: {:#?}",
block_status,
tx_in_block.block_hash()
);
}, },
TxStatus::Error { message } TxStatus::Error { message }
| TxStatus::Invalid { message } | TxStatus::Invalid { message }
@@ -29,9 +29,7 @@ pub fn parse(input: &str) -> Result<MetricMap, ParserError> {
let mut pairs = MetricsParser::parse(Rule::statement, input) let mut pairs = MetricsParser::parse(Rule::statement, input)
.map_err(|e| ParserError::ParseError(Box::new(e)))?; .map_err(|e| ParserError::ParseError(Box::new(e)))?;
let root = pairs let root = pairs.next().ok_or(ParserError::ParseRootNodeError(pairs.as_str().to_string()))?;
.next()
.ok_or(ParserError::ParseRootNodeError(pairs.as_str().to_string()))?;
for token in root.into_inner() { for token in root.into_inner() {
if token.as_rule() == Rule::block { if token.as_rule() == Rule::block {
let inner = token.into_inner(); let inner = token.into_inner();
@@ -148,15 +146,10 @@ mod tests {
&1_f64 &1_f64
); );
// with prefix and no chain // with prefix and no chain
assert_eq!( assert_eq!(metrics.get("polkadot_node_is_active_validator").unwrap(), &1_f64);
metrics.get("polkadot_node_is_active_validator").unwrap(),
&1_f64
);
// no prefix with chain // no prefix with chain
assert_eq!( assert_eq!(
metrics metrics.get("node_is_active_validator{chain=\"rococo_local_testnet\"}").unwrap(),
.get("node_is_active_validator{chain=\"rococo_local_testnet\"}")
.unwrap(),
&1_f64 &1_f64
); );
// no prefix without chain // no prefix without chain
@@ -106,11 +106,7 @@ impl ContainerRunOptions {
{ {
ContainerRunOptions { ContainerRunOptions {
image: image.to_string(), image: image.to_string(),
command: command command: command.clone().into_iter().map(|s| s.into()).collect::<Vec<_>>(),
.clone()
.into_iter()
.map(|s| s.into())
.collect::<Vec<_>>(),
env: None, env: None,
volume_mounts: None, volume_mounts: None,
name: None, name: None,
@@ -125,11 +121,7 @@ impl ContainerRunOptions {
where where
S: Into<String> + std::fmt::Debug + Send + Clone, S: Into<String> + std::fmt::Debug + Send + Clone,
{ {
self.env = Some( self.env = Some(env.into_iter().map(|(name, value)| (name.into(), value.into())).collect());
env.into_iter()
.map(|(name, value)| (name.into(), value.into()))
.collect(),
);
self self
} }
@@ -186,23 +178,13 @@ impl DockerClient {
} }
pub fn client_binary(&self) -> String { pub fn client_binary(&self) -> String {
String::from(if self.using_podman { String::from(if self.using_podman { "podman" } else { "docker" })
"podman"
} else {
"docker"
})
} }
async fn is_using_podman() -> Result<bool> { async fn is_using_podman() -> Result<bool> {
if let Ok(output) = tokio::process::Command::new("docker") if let Ok(output) = tokio::process::Command::new("docker").arg("version").output().await {
.arg("version")
.output()
.await
{
// detect whether we're actually running podman with docker emulation // detect whether we're actually running podman with docker emulation
return Ok(String::from_utf8_lossy(&output.stdout) return Ok(String::from_utf8_lossy(&output.stdout).to_lowercase().contains("podman"));
.to_lowercase()
.contains("podman"));
} }
tokio::process::Command::new("podman") tokio::process::Command::new("podman")
@@ -326,12 +308,7 @@ impl DockerClient {
cmd.arg(name); cmd.arg(name);
cmd.args( cmd.args(command.clone().into_iter().map(|s| <S as Into<String>>::into(s)));
command
.clone()
.into_iter()
.map(|s| <S as Into<String>>::into(s)),
);
trace!("cmd is : {:?}", cmd); trace!("cmd is : {:?}", cmd);
@@ -348,10 +325,7 @@ impl DockerClient {
})?; })?;
if !result.status.success() { if !result.status.success() {
return Ok(Err(( return Ok(Err((result.status, String::from_utf8_lossy(&result.stderr).to_string())));
result.status,
String::from_utf8_lossy(&result.stderr).to_string(),
)));
} }
Ok(Ok(String::from_utf8_lossy(&result.stdout).to_string())) Ok(Ok(String::from_utf8_lossy(&result.stdout).to_string()))
@@ -438,10 +412,8 @@ impl DockerClient {
.collect(); .collect();
info!("{:?}", container_names); info!("{:?}", container_names);
let futures = container_names let futures =
.iter() container_names.iter().map(|name| self.container_rm(name)).collect::<Vec<_>>();
.map(|name| self.container_rm(name))
.collect::<Vec<_>>();
try_join_all(futures).await?; try_join_all(futures).await?;
Ok(()) Ok(())
@@ -452,12 +424,7 @@ impl DockerClient {
"127.0.0.1".into() "127.0.0.1".into()
} else { } else {
let mut cmd = tokio::process::Command::new("docker"); let mut cmd = tokio::process::Command::new("docker");
cmd.args(vec![ cmd.args(vec!["inspect", "-f", "{{ .NetworkSettings.IPAddress }}", container_name]);
"inspect",
"-f",
"{{ .NetworkSettings.IPAddress }}",
container_name,
]);
trace!("CMD: {cmd:?}"); trace!("CMD: {cmd:?}");
@@ -478,17 +445,9 @@ impl DockerClient {
async fn get_containers(&self) -> Result<Vec<Container>> { async fn get_containers(&self) -> Result<Vec<Container>> {
let containers = if self.using_podman { let containers = if self.using_podman {
self.get_podman_containers() self.get_podman_containers().await?.into_iter().map(Container::Podman).collect()
.await?
.into_iter()
.map(Container::Podman)
.collect()
} else { } else {
self.get_docker_containers() self.get_docker_containers().await?.into_iter().map(Container::Docker).collect()
.await?
.into_iter()
.map(Container::Docker)
.collect()
}; };
Ok(containers) Ok(containers)
@@ -131,16 +131,11 @@ where
PathBuf::from_iter([&self.base_dir, &PathBuf::from("zombie-wrapper.sh")]); PathBuf::from_iter([&self.base_dir, &PathBuf::from("zombie-wrapper.sh")]);
self.filesystem self.filesystem
.write( .write(&local_zombie_wrapper_path, include_str!("../shared/scripts/zombie-wrapper.sh"))
&local_zombie_wrapper_path,
include_str!("../shared/scripts/zombie-wrapper.sh"),
)
.await?; .await?;
let local_helper_binaries_downloader_path = PathBuf::from_iter([ let local_helper_binaries_downloader_path =
&self.base_dir, PathBuf::from_iter([&self.base_dir, &PathBuf::from("helper-binaries-downloader.sh")]);
&PathBuf::from("helper-binaries-downloader.sh"),
]);
self.filesystem self.filesystem
.write( .write(
@@ -351,10 +346,7 @@ where
}) })
.await?; .await?;
self.nodes self.nodes.write().await.insert(node.name().to_string(), node.clone());
.write()
.await
.insert(node.name().to_string(), node.clone());
Ok(node) Ok(node)
} }
@@ -375,10 +367,7 @@ where
let node = DockerNode::attach_to_live(options).await?; let node = DockerNode::attach_to_live(options).await?;
self.nodes self.nodes.write().await.insert(node.name().to_string(), node.clone());
.write()
.await
.insert(node.name().to_string(), node.clone());
Ok(node) Ok(node)
} }
@@ -386,9 +375,7 @@ where
async fn generate_files(&self, options: GenerateFilesOptions) -> Result<(), ProviderError> { async fn generate_files(&self, options: GenerateFilesOptions) -> Result<(), ProviderError> {
debug!("generate files options {options:#?}"); debug!("generate files options {options:#?}");
let node_name = options let node_name = options.temp_name.unwrap_or_else(|| format!("temp-{}", Uuid::new_v4()));
.temp_name
.unwrap_or_else(|| format!("temp-{}", Uuid::new_v4()));
let node_image = options.image.expect(&format!( let node_image = options.image.expect(&format!(
"image should be present when generating files with docker provider {THIS_IS_A_BUG}" "image should be present when generating files with docker provider {THIS_IS_A_BUG}"
)); ));
@@ -402,21 +389,11 @@ where
) )
.await?; .await?;
for GenerateFileCommand { for GenerateFileCommand { program, args, env, local_output_path } in options.commands {
program,
args,
env,
local_output_path,
} in options.commands
{
let local_output_full_path = format!( let local_output_full_path = format!(
"{}{}{}", "{}{}{}",
self.base_dir.to_string_lossy(), self.base_dir.to_string_lossy(),
if local_output_path.starts_with("/") { if local_output_path.starts_with("/") { "" } else { "/" },
""
} else {
"/"
},
local_output_path.to_string_lossy() local_output_path.to_string_lossy()
); );
@@ -440,11 +417,10 @@ where
} }
async fn destroy(&self) -> Result<(), ProviderError> { async fn destroy(&self) -> Result<(), ProviderError> {
let _ = self let _ =
.docker_client self.docker_client.namespaced_containers_rm(&self.name).await.map_err(|err| {
.namespaced_containers_rm(&self.name) ProviderError::DeleteNamespaceFailed(self.name.clone(), err.into())
.await })?;
.map_err(|err| ProviderError::DeleteNamespaceFailed(self.name.clone(), err.into()))?;
if let Some(provider) = self.provider.upgrade() { if let Some(provider) = self.provider.upgrade() {
provider.namespaces.write().await.remove(&self.name); provider.namespaces.write().await.remove(&self.name);
@@ -237,14 +237,8 @@ where
format!("{}-helper-binaries", self.namespace_name()), format!("{}-helper-binaries", self.namespace_name()),
"/helpers".to_string(), "/helpers".to_string(),
), ),
( (self.config_dir.to_string_lossy().into_owned(), "/cfg".to_string()),
self.config_dir.to_string_lossy().into_owned(), (self.data_dir.to_string_lossy().into_owned(), "/data".to_string()),
"/cfg".to_string(),
),
(
self.data_dir.to_string_lossy().into_owned(),
"/data".to_string(),
),
( (
self.relay_data_dir.to_string_lossy().into_owned(), self.relay_data_dir.to_string_lossy().into_owned(),
"/relay-data".to_string(), "/relay-data".to_string(),
@@ -435,11 +429,7 @@ where
} }
fn log_cmd(&self) -> String { fn log_cmd(&self) -> String {
format!( format!("{} logs -f {}", self.docker_client.client_binary(), self.container_name)
"{} logs -f {}",
self.docker_client.client_binary(),
self.container_name
)
} }
fn path_in_node(&self, file: &Path) -> PathBuf { fn path_in_node(&self, file: &Path) -> PathBuf {
@@ -470,23 +460,14 @@ where
&self, &self,
options: RunCommandOptions, options: RunCommandOptions,
) -> Result<ExecutionResult, ProviderError> { ) -> Result<ExecutionResult, ProviderError> {
debug!( debug!("running command for {} with options {:?}", self.name, options);
"running command for {} with options {:?}",
self.name, options
);
let command = [vec![options.program], options.args].concat(); let command = [vec![options.program], options.args].concat();
self.docker_client self.docker_client
.container_exec( .container_exec(
&self.container_name, &self.container_name,
vec!["sh", "-c", &command.join(" ")], vec!["sh", "-c", &command.join(" ")],
Some( Some(options.env.iter().map(|(k, v)| (k.as_ref(), v.as_ref())).collect()),
options
.env
.iter()
.map(|(k, v)| (k.as_ref(), v.as_ref()))
.collect(),
),
None, None,
) )
.await .await
@@ -565,11 +546,7 @@ where
} }
async fn ip(&self) -> Result<IpAddr, ProviderError> { async fn ip(&self) -> Result<IpAddr, ProviderError> {
let ip = self let ip = self.docker_client.container_ip(&self.container_name).await.map_err(|err| {
.docker_client
.container_ip(&self.container_name)
.await
.map_err(|err| {
ProviderError::InvalidConfig(format!("Error getting container ip, err: {err}")) ProviderError::InvalidConfig(format!("Error getting container ip, err: {err}"))
})?; })?;
@@ -105,10 +105,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -127,10 +124,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -151,10 +145,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -121,20 +121,12 @@ impl KubernetesClient {
labels: Some(labels), labels: Some(labels),
..Default::default() ..Default::default()
}, },
data: Some(BTreeMap::from([( data: Some(BTreeMap::from([(file_name.to_string(), file_contents.to_string())])),
file_name.to_string(),
file_contents.to_string(),
)])),
..Default::default() ..Default::default()
}; };
config_maps config_maps.create(&PostParams::default(), &config_map).await.map_err(|err| {
.create(&PostParams::default(), &config_map) Error::from(anyhow!("error while creating config map {name} for {file_name}: {err}"))
.await
.map_err(|err| {
Error::from(anyhow!(
"error while creating config map {name} for {file_name}: {err}"
))
})?; })?;
self.wait_created(config_maps, name).await?; self.wait_created(config_maps, name).await?;
@@ -169,9 +161,8 @@ impl KubernetesClient {
trace!("Pod {name} checking for ready state!"); trace!("Pod {name} checking for ready state!");
let wait_ready = await_condition(pods, name, helpers::is_pod_ready()); let wait_ready = await_condition(pods, name, helpers::is_pod_ready());
// TODO: we should use the `node_spawn_timeout` from global settings here. // TODO: we should use the `node_spawn_timeout` from global settings here.
let _ = tokio::time::timeout(Duration::from_secs(600), wait_ready) let _ =
.await tokio::time::timeout(Duration::from_secs(600), wait_ready).await.map_err(|err| {
.map_err(|err| {
Error::from(anyhow!("error while awaiting pod {name} running: {err}")) Error::from(anyhow!("error while awaiting pod {name} running: {err}"))
})?; })?;
@@ -181,14 +172,7 @@ impl KubernetesClient {
pub(super) async fn pod_logs(&self, namespace: &str, name: &str) -> Result<String> { pub(super) async fn pod_logs(&self, namespace: &str, name: &str) -> Result<String> {
Api::<Pod>::namespaced(self.inner.clone(), namespace) Api::<Pod>::namespaced(self.inner.clone(), namespace)
.logs( .logs(name, &LogParams { pretty: true, timestamps: true, ..Default::default() })
name,
&LogParams {
pretty: true,
timestamps: true,
..Default::default()
},
)
.await .await
.map_err(|err| Error::from(anyhow!("error while getting logs for pod {name}: {err}"))) .map_err(|err| Error::from(anyhow!("error while getting logs for pod {name}: {err}")))
} }
@@ -199,9 +183,8 @@ impl KubernetesClient {
.await .await
.map_err(|err| Error::from(anyhow!("error while getting pod {name}: {err}")))?; .map_err(|err| Error::from(anyhow!("error while getting pod {name}: {err}")))?;
let status = pod.status.ok_or(Error::from(anyhow!( let status =
"error while getting status for pod {name}" pod.status.ok_or(Error::from(anyhow!("error while getting status for pod {name}")))?;
)))?;
Ok(status) Ok(status)
} }
@@ -224,9 +207,7 @@ impl KubernetesClient {
) )
.await .await
.map_err(|err| { .map_err(|err| {
Error::from(anyhow!( Error::from(anyhow!("error while getting a log stream for {name}: {err}"))
"error while getting a log stream for {name}: {err}"
))
})? })?
.compat(), .compat(),
)) ))
@@ -243,25 +224,21 @@ impl KubernetesClient {
{ {
trace!("running command: {command:?} on pod {name} for ns {namespace}"); trace!("running command: {command:?} on pod {name} for ns {namespace}");
let mut process = Api::<Pod>::namespaced(self.inner.clone(), namespace) let mut process = Api::<Pod>::namespaced(self.inner.clone(), namespace)
.exec( .exec(name, command, &AttachParams::default().stdout(true).stderr(true))
name,
command,
&AttachParams::default().stdout(true).stderr(true),
)
.await .await
.map_err(|err| Error::from(anyhow!("error while exec in the pod {name}: {err}")))?; .map_err(|err| Error::from(anyhow!("error while exec in the pod {name}: {err}")))?;
let stdout_stream = process.stdout().expect(&format!( let stdout_stream = process
"stdout shouldn't be None when true passed to exec {THIS_IS_A_BUG}" .stdout()
)); .expect(&format!("stdout shouldn't be None when true passed to exec {THIS_IS_A_BUG}"));
let stdout = tokio_util::io::ReaderStream::new(stdout_stream) let stdout = tokio_util::io::ReaderStream::new(stdout_stream)
.filter_map(|r| async { r.ok().and_then(|v| String::from_utf8(v.to_vec()).ok()) }) .filter_map(|r| async { r.ok().and_then(|v| String::from_utf8(v.to_vec()).ok()) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.await .await
.join(""); .join("");
let stderr_stream = process.stderr().expect(&format!( let stderr_stream = process
"stderr shouldn't be None when true passed to exec {THIS_IS_A_BUG}" .stderr()
)); .expect(&format!("stderr shouldn't be None when true passed to exec {THIS_IS_A_BUG}"));
let stderr = tokio_util::io::ReaderStream::new(stderr_stream) let stderr = tokio_util::io::ReaderStream::new(stderr_stream)
.filter_map(|r| async { r.ok().and_then(|v| String::from_utf8(v.to_vec()).ok()) }) .filter_map(|r| async { r.ok().and_then(|v| String::from_utf8(v.to_vec()).ok()) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
@@ -270,16 +247,12 @@ impl KubernetesClient {
let status = process let status = process
.take_status() .take_status()
.expect(&format!( .expect(&format!("first call to status shouldn't fail {THIS_IS_A_BUG}"))
"first call to status shouldn't fail {THIS_IS_A_BUG}"
))
.await; .await;
// await process to finish // await process to finish
process.join().await.map_err(|err| { process.join().await.map_err(|err| {
Error::from(anyhow!( Error::from(anyhow!("error while joining process during exec for {name}: {err}"))
"error while joining process during exec for {name}: {err}"
))
})?; })?;
match status { match status {
@@ -334,12 +307,8 @@ impl KubernetesClient {
.await .await
.map_err(|err| Error::from(anyhow!("error when deleting pod {name}: {err}")))?; .map_err(|err| Error::from(anyhow!("error when deleting pod {name}: {err}")))?;
await_condition(pods, name, conditions::is_deleted(name)) await_condition(pods, name, conditions::is_deleted(name)).await.map_err(|err| {
.await Error::from(anyhow!("error when waiting for pod {name} to be deleted: {err}"))
.map_err(|err| {
Error::from(anyhow!(
"error when waiting for pod {name} to be deleted: {err}"
))
})?; })?;
Ok(()) Ok(())
@@ -381,12 +350,8 @@ impl KubernetesClient {
remote_port: u16, remote_port: u16,
) -> Result<(u16, JoinHandle<()>)> { ) -> Result<(u16, JoinHandle<()>)> {
let pods = Api::<Pod>::namespaced(self.inner.clone(), namespace); let pods = Api::<Pod>::namespaced(self.inner.clone(), namespace);
let bind = TcpListener::bind((LOCALHOST, local_port)) let bind = TcpListener::bind((LOCALHOST, local_port)).await.map_err(|err| {
.await Error::from(anyhow!("error binding port {local_port} for pod {name}: {err}"))
.map_err(|err| {
Error::from(anyhow!(
"error binding port {local_port} for pod {name}: {err}"
))
})?; })?;
let local_port = bind.local_addr().map_err(|err| Error(err.into()))?.port(); let local_port = bind.local_addr().map_err(|err| Error(err.into()))?.port();
let name = name.to_string(); let name = name.to_string();
@@ -523,15 +488,10 @@ impl KubernetesClient {
let ar = ApiResource::from_gvk(&gvk); let ar = ApiResource::from_gvk(&gvk);
let api: Api<DynamicObject> = Api::namespaced_with(self.inner.clone(), namespace, &ar); let api: Api<DynamicObject> = Api::namespaced_with(self.inner.clone(), namespace, &ar);
api.create( api.create(&PostParams::default(), &serde_yaml::from_str(raw_manifest).unwrap())
&PostParams::default(),
&serde_yaml::from_str(raw_manifest).unwrap(),
)
.await .await
.map_err(|err| { .map_err(|err| {
Error::from(anyhow!( Error::from(anyhow!("error while creating static-config {raw_manifest}: {err}"))
"error while creating static-config {raw_manifest}: {err}"
))
})?; })?;
Ok(()) Ok(())
@@ -175,25 +175,13 @@ where
async fn initialize_k8s(&self) -> Result<(), ProviderError> { async fn initialize_k8s(&self) -> Result<(), ProviderError> {
// TODO (javier): check with Hamid if we are using this labels in any scheduling logic. // TODO (javier): check with Hamid if we are using this labels in any scheduling logic.
let labels = BTreeMap::from([ let labels = BTreeMap::from([
( ("jobId".to_string(), env::var("CI_JOB_ID").unwrap_or("".to_string())),
"jobId".to_string(), ("projectName".to_string(), env::var("CI_PROJECT_NAME").unwrap_or("".to_string())),
env::var("CI_JOB_ID").unwrap_or("".to_string()), ("projectId".to_string(), env::var("CI_PROJECT_ID").unwrap_or("".to_string())),
),
(
"projectName".to_string(),
env::var("CI_PROJECT_NAME").unwrap_or("".to_string()),
),
(
"projectId".to_string(),
env::var("CI_PROJECT_ID").unwrap_or("".to_string()),
),
]); ]);
let manifest = self let manifest =
.k8s_client self.k8s_client.create_namespace(&self.name, labels).await.map_err(|err| {
.create_namespace(&self.name, labels)
.await
.map_err(|err| {
ProviderError::CreateNamespaceFailed(self.name.to_string(), err.into()) ProviderError::CreateNamespaceFailed(self.name.to_string(), err.into())
})?; })?;
@@ -204,9 +192,7 @@ where
let dest_path = let dest_path =
PathBuf::from_iter([&self.base_dir, &PathBuf::from("namespace_manifest.yaml")]); PathBuf::from_iter([&self.base_dir, &PathBuf::from("namespace_manifest.yaml")]);
self.filesystem self.filesystem.write(dest_path, serialized_manifest).await?;
.write(dest_path, serialized_manifest)
.await?;
Ok(()) Ok(())
} }
@@ -218,10 +204,7 @@ where
); );
// Apply NetworkPolicy manifest // Apply NetworkPolicy manifest
self.k8s_client self.k8s_client.create_static_resource(&self.name, &np_manifest).await.map_err(|err| {
.create_static_resource(&self.name, &np_manifest)
.await
.map_err(|err| {
ProviderError::CreateNamespaceFailed(self.name.to_string(), err.into()) ProviderError::CreateNamespaceFailed(self.name.to_string(), err.into())
})?; })?;
@@ -254,10 +237,7 @@ where
name: name.clone(), name: name.clone(),
image: Some(FILE_SERVER_IMAGE.to_string()), image: Some(FILE_SERVER_IMAGE.to_string()),
image_pull_policy: Some("Always".to_string()), image_pull_policy: Some("Always".to_string()),
ports: Some(vec![ContainerPort { ports: Some(vec![ContainerPort { container_port: 80, ..Default::default() }]),
container_port: 80,
..Default::default()
}]),
startup_probe: Some(Probe { startup_probe: Some(Probe {
http_get: Some(HTTPGetAction { http_get: Some(HTTPGetAction {
path: Some("/".to_string()), path: Some("/".to_string()),
@@ -285,21 +265,14 @@ where
let pod_serialized_manifest = serde_yaml::to_string(&pod_manifest) let pod_serialized_manifest = serde_yaml::to_string(&pod_manifest)
.map_err(|err| ProviderError::FileServerSetupError(err.into()))?; .map_err(|err| ProviderError::FileServerSetupError(err.into()))?;
let pod_dest_path = PathBuf::from_iter([ let pod_dest_path =
&self.base_dir, PathBuf::from_iter([&self.base_dir, &PathBuf::from("file_server_pod_manifest.yaml")]);
&PathBuf::from("file_server_pod_manifest.yaml"),
]);
self.filesystem self.filesystem.write(pod_dest_path, pod_serialized_manifest).await?;
.write(pod_dest_path, pod_serialized_manifest)
.await?;
let service_spec = ServiceSpec { let service_spec = ServiceSpec {
selector: Some(labels.clone()), selector: Some(labels.clone()),
ports: Some(vec![ServicePort { ports: Some(vec![ServicePort { port: 80, ..Default::default() }]),
port: 80,
..Default::default()
}]),
..Default::default() ..Default::default()
}; };
@@ -317,9 +290,7 @@ where
&PathBuf::from("file_server_service_manifest.yaml"), &PathBuf::from("file_server_service_manifest.yaml"),
]); ]);
self.filesystem self.filesystem.write(service_dest_path, serialized_service_manifest).await?;
.write(service_dest_path, serialized_service_manifest)
.await?;
self.setup_file_server_port_fwd(&name).await?; self.setup_file_server_port_fwd(&name).await?;
@@ -366,9 +337,7 @@ where
let dest_path = PathBuf::from_iter([&self.base_dir, &PathBuf::from(local_manifest_name)]); let dest_path = PathBuf::from_iter([&self.base_dir, &PathBuf::from(local_manifest_name)]);
self.filesystem self.filesystem.write(dest_path, serializer_manifest).await?;
.write(dest_path, serializer_manifest)
.await?;
Ok(()) Ok(())
} }
@@ -496,10 +465,7 @@ where
}) })
.await?; .await?;
self.nodes self.nodes.write().await.insert(node.name().to_string(), node.clone());
.write()
.await
.insert(node.name().to_string(), node.clone());
Ok(node) Ok(node)
} }
@@ -520,10 +486,7 @@ where
let node = KubernetesNode::attach_to_live(options).await?; let node = KubernetesNode::attach_to_live(options).await?;
self.nodes self.nodes.write().await.insert(node.name().to_string(), node.clone());
.write()
.await
.insert(node.name().to_string(), node.clone());
Ok(node) Ok(node)
} }
@@ -531,9 +494,7 @@ where
async fn generate_files(&self, options: GenerateFilesOptions) -> Result<(), ProviderError> { async fn generate_files(&self, options: GenerateFilesOptions) -> Result<(), ProviderError> {
debug!("generate files options {options:#?}"); debug!("generate files options {options:#?}");
let node_name = options let node_name = options.temp_name.unwrap_or_else(|| format!("temp-{}", Uuid::new_v4()));
.temp_name
.unwrap_or_else(|| format!("temp-{}", Uuid::new_v4()));
let node_image = options let node_image = options
.image .image
.expect(&format!("image should be present when generating files with kubernetes provider {THIS_IS_A_BUG}")); .expect(&format!("image should be present when generating files with kubernetes provider {THIS_IS_A_BUG}"));
@@ -547,21 +508,11 @@ where
) )
.await?; .await?;
for GenerateFileCommand { for GenerateFileCommand { program, args, env, local_output_path } in options.commands {
program,
args,
env,
local_output_path,
} in options.commands
{
let local_output_full_path = format!( let local_output_full_path = format!(
"{}{}{}", "{}{}{}",
self.base_dir.to_string_lossy(), self.base_dir.to_string_lossy(),
if local_output_path.starts_with("/") { if local_output_path.starts_with("/") { "" } else { "/" },
""
} else {
"/"
},
local_output_path.to_string_lossy() local_output_path.to_string_lossy()
); );
@@ -585,11 +536,10 @@ where
} }
async fn destroy(&self) -> Result<(), ProviderError> { async fn destroy(&self) -> Result<(), ProviderError> {
let _ = self let _ =
.k8s_client self.k8s_client.delete_namespace(&self.name).await.map_err(|err| {
.delete_namespace(&self.name) ProviderError::DeleteNamespaceFailed(self.name.clone(), err.into())
.await })?;
.map_err(|err| ProviderError::DeleteNamespaceFailed(self.name.clone(), err.into()))?;
if let Some(provider) = self.provider.upgrade() { if let Some(provider) = self.provider.upgrade() {
provider.namespaces.write().await.remove(&self.name); provider.namespaces.write().await.remove(&self.name);
@@ -231,10 +231,7 @@ where
async fn initialize_k8s(&self) -> Result<(), ProviderError> { async fn initialize_k8s(&self) -> Result<(), ProviderError> {
let labels = BTreeMap::from([ let labels = BTreeMap::from([
( ("app.kubernetes.io/name".to_string(), self.name().to_string()),
"app.kubernetes.io/name".to_string(),
self.name().to_string(),
),
( (
"x-infra-instance".to_string(), "x-infra-instance".to_string(),
env::var("X_INFRA_INSTANCE").unwrap_or("ondemand".to_string()), env::var("X_INFRA_INSTANCE").unwrap_or("ondemand".to_string()),
@@ -312,9 +309,7 @@ where
&PathBuf::from(format!("{}_svc_manifest.yaml", &self.name)), &PathBuf::from(format!("{}_svc_manifest.yaml", &self.name)),
]); ]);
self.filesystem self.filesystem.write(service_dest_path, serialized_service_manifest).await?;
.write(service_dest_path, serialized_service_manifest)
.await?;
Ok(()) Ok(())
} }
@@ -471,12 +466,7 @@ where
if res.status() != reqwest::StatusCode::OK { if res.status() != reqwest::StatusCode::OK {
// we need to upload the file // we need to upload the file
self.http_client self.http_client.post(url.as_ref()).body(data).send().await.map_err(|err| {
.post(url.as_ref())
.body(data)
.send()
.await
.map_err(|err| {
ProviderError::UploadFile(location.to_string_lossy().to_string(), err.into()) ProviderError::UploadFile(location.to_string_lossy().to_string(), err.into())
})?; })?;
} }
@@ -491,9 +481,7 @@ where
} }
} }
Err(ProviderError::FileServerSetupError(anyhow!( Err(ProviderError::FileServerSetupError(anyhow!("file server port not bound locally")))
"file server port not bound locally"
)))
} }
async fn download_file( async fn download_file(
@@ -507,12 +495,7 @@ where
.pod_exec( .pod_exec(
&self.namespace_name(), &self.namespace_name(),
&self.name, &self.name,
vec![ vec!["/cfg/curl", url, "--output", &remote_file_path.to_string_lossy()],
"/cfg/curl",
url,
"--output",
&remote_file_path.to_string_lossy(),
],
) )
.await .await
.map_err(|err| { .map_err(|err| {
@@ -538,11 +521,7 @@ where
.pod_exec( .pod_exec(
&self.namespace_name(), &self.namespace_name(),
&self.name, &self.name,
vec![ vec!["/cfg/coreutils", "sha256sum", &remote_file_path.to_string_lossy()],
"/cfg/coreutils",
"sha256sum",
&remote_file_path.to_string_lossy(),
],
) )
.await .await
.map_err(|err| { .map_err(|err| {
@@ -657,10 +636,7 @@ where
.await .await
.map_err(|err| ProviderError::PortForwardError(local_port, remote_port, err.into()))?; .map_err(|err| ProviderError::PortForwardError(local_port, remote_port, err.into()))?;
self.port_fwds self.port_fwds.write().await.insert(remote_port, (port, task));
.write()
.await
.insert(remote_port, (port, task));
Ok(Some(port)) Ok(Some(port))
} }
@@ -682,11 +658,7 @@ where
} }
self.k8s_client self.k8s_client
.pod_exec( .pod_exec(&self.namespace_name(), &self.name, vec!["sh", "-c", &command.join(" ")])
&self.namespace_name(),
&self.name,
vec!["sh", "-c", &command.join(" ")],
)
.await .await
.map_err(|err| { .map_err(|err| {
ProviderError::RunCommandError( ProviderError::RunCommandError(
@@ -704,9 +676,7 @@ where
let file_name = options let file_name = options
.local_script_path .local_script_path
.file_name() .file_name()
.expect(&format!( .expect(&format!("file name should be present at this point {THIS_IS_A_BUG}"))
"file name should be present at this point {THIS_IS_A_BUG}"
))
.to_string_lossy(); .to_string_lossy();
self.run_command(RunCommandOptions { self.run_command(RunCommandOptions {
@@ -747,9 +717,7 @@ where
tokio::time::sleep(Duration::from_secs(i)).await; tokio::time::sleep(Duration::from_secs(i)).await;
} }
let res = self let res = self.download_file(url.as_ref(), remote_file_path, Some(&hash)).await;
.download_file(url.as_ref(), remote_file_path, Some(&hash))
.await;
last_err = res.err(); last_err = res.err();
@@ -803,10 +771,7 @@ where
ProviderError::InvalidConfig(format!("Can not parse the pod ip: {ip}, err: {err}")) ProviderError::InvalidConfig(format!("Can not parse the pod ip: {ip}, err: {err}"))
})?) })?)
} else { } else {
Err(ProviderError::InvalidConfig(format!( Err(ProviderError::InvalidConfig(format!("Can not find ip of pod: {}", self.name())))
"Can not find ip of pod: {}",
self.name()
)))
} }
} }
@@ -44,10 +44,7 @@ impl PodSpecBuilder {
image: Some(image.to_string()), image: Some(image.to_string()),
image_pull_policy: Some("Always".to_string()), image_pull_policy: Some("Always".to_string()),
command: Some( command: Some(
[ [vec!["/zombie-wrapper.sh".to_string(), program.to_string()], args.to_vec()]
vec!["/zombie-wrapper.sh".to_string(), program.to_string()],
args.to_vec(),
]
.concat(), .concat(),
), ),
env: Some( env: Some(
@@ -91,18 +88,9 @@ impl PodSpecBuilder {
fn build_volumes() -> Vec<Volume> { fn build_volumes() -> Vec<Volume> {
vec![ vec![
Volume { Volume { name: "cfg".to_string(), ..Default::default() },
name: "cfg".to_string(), Volume { name: "data".to_string(), ..Default::default() },
..Default::default() Volume { name: "relay-data".to_string(), ..Default::default() },
},
Volume {
name: "data".to_string(),
..Default::default()
},
Volume {
name: "relay-data".to_string(),
..Default::default()
},
Volume { Volume {
name: "zombie-wrapper-volume".to_string(), name: "zombie-wrapper-volume".to_string(),
config_map: Some(ConfigMapVolumeSource { config_map: Some(ConfigMapVolumeSource {
@@ -89,10 +89,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -111,10 +108,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -135,10 +129,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -166,10 +166,7 @@ where
}) })
.await?; .await?;
self.nodes self.nodes.write().await.insert(options.name.clone(), node.clone());
.write()
.await
.insert(options.name.clone(), node.clone());
Ok(node) Ok(node)
} }
@@ -194,10 +191,7 @@ where
as i32; as i32;
let node = NativeNode::attach_to_live(options, pid).await?; let node = NativeNode::attach_to_live(options, pid).await?;
self.nodes self.nodes.write().await.insert(node.name().to_string(), node.clone());
.write()
.await
.insert(node.name().to_string(), node.clone());
Ok(node) Ok(node)
} }
@@ -218,13 +212,7 @@ where
) )
.await?; .await?;
for GenerateFileCommand { for GenerateFileCommand { program, args, env, local_output_path } in options.commands {
program,
args,
env,
local_output_path,
} in options.commands
{
trace!( trace!(
"🏗 building file {:?} in path {} with command {} {}", "🏗 building file {:?} in path {} with command {} {}",
local_output_path.as_os_str(), local_output_path.as_os_str(),
@@ -235,11 +223,7 @@ where
let local_output_full_path = format!( let local_output_full_path = format!(
"{}{}{}", "{}{}{}",
self.base_dir.to_string_lossy(), self.base_dir.to_string_lossy(),
if local_output_path.starts_with("/") { if local_output_path.starts_with("/") { "" } else { "/" },
""
} else {
"/"
},
local_output_path.to_string_lossy() local_output_path.to_string_lossy()
); );
@@ -329,16 +313,11 @@ mod tests {
let cmd = GenerateFileCommand::new(program, out_name.clone()).args(args); let cmd = GenerateFileCommand::new(program, out_name.clone()).args(args);
let options = GenerateFilesOptions::new(vec![cmd], None, Some(expected_path.clone())); let options = GenerateFilesOptions::new(vec![cmd], None, Some(expected_path.clone()));
ns.generate_files(options) ns.generate_files(options).await.expect("generation should succeed");
.await
.expect("generation should succeed");
// Read produced file from namespace base_dir // Read produced file from namespace base_dir
let produced_path = base_dir.join(out_name); let produced_path = base_dir.join(out_name);
let produced = fs let produced = fs.read_to_string(&produced_path).await.expect("should read produced file");
.read_to_string(&produced_path)
.await
.expect("should read produced file");
assert_eq!(produced, "{\"hello\":\"world\"}"); assert_eq!(produced, "{\"hello\":\"world\"}");
} }
@@ -360,15 +339,10 @@ mod tests {
let cmd = GenerateFileCommand::new(program, out_name.clone()).args(args); let cmd = GenerateFileCommand::new(program, out_name.clone()).args(args);
let options = GenerateFilesOptions::new(vec![cmd], None, None); let options = GenerateFilesOptions::new(vec![cmd], None, None);
ns.generate_files(options) ns.generate_files(options).await.expect("generation should succeed");
.await
.expect("generation should succeed");
let produced_path = base_dir.join(out_name); let produced_path = base_dir.join(out_name);
let produced = fs let produced = fs.read_to_string(&produced_path).await.expect("should read produced file");
.read_to_string(&produced_path)
.await
.expect("should read produced file");
assert_eq!(produced, "42"); assert_eq!(produced, "42");
} }
} }
@@ -300,9 +300,7 @@ where
let contents = self.filesystem.read(&full_path).await.unwrap(); let contents = self.filesystem.read(&full_path).await.unwrap();
let gz = GzDecoder::new(&contents[..]); let gz = GzDecoder::new(&contents[..]);
let mut archive = Archive::new(gz); let mut archive = Archive::new(gz);
archive archive.unpack(self.base_dir.to_string_lossy().as_ref()).unwrap();
.unpack(self.base_dir.to_string_lossy().as_ref())
.unwrap();
if std::env::var("ZOMBIE_RM_TGZ_AFTER_EXTRACT").is_ok() { if std::env::var("ZOMBIE_RM_TGZ_AFTER_EXTRACT").is_ok() {
let res = fs::remove_file(&full_path).await; let res = fs::remove_file(&full_path).await;
@@ -337,9 +335,8 @@ where
} }
async fn initialize_process(&self) -> Result<(ChildStdout, ChildStderr), ProviderError> { async fn initialize_process(&self) -> Result<(ChildStdout, ChildStderr), ProviderError> {
let filtered_env: HashMap<String, String> = env::vars() let filtered_env: HashMap<String, String> =
.filter(|(k, _)| k == "TZ" || k == "LANG" || k == "PATH") env::vars().filter(|(k, _)| k == "TZ" || k == "LANG" || k == "PATH").collect();
.collect();
let mut process = Command::new(&self.program) let mut process = Command::new(&self.program)
.args(&self.args) .args(&self.args)
@@ -353,14 +350,10 @@ where
.current_dir(&self.base_dir) .current_dir(&self.base_dir)
.spawn() .spawn()
.map_err(|err| ProviderError::NodeSpawningFailed(self.name.to_string(), err.into()))?; .map_err(|err| ProviderError::NodeSpawningFailed(self.name.to_string(), err.into()))?;
let stdout = process let stdout =
.stdout process.stdout.take().expect(&format!("infaillible, stdout is piped {THIS_IS_A_BUG}"));
.take() let stderr =
.expect(&format!("infaillible, stdout is piped {THIS_IS_A_BUG}")); process.stderr.take().expect(&format!("infaillible, stderr is piped {THIS_IS_A_BUG}"));
let stderr = process
.stderr
.take()
.expect(&format!("infaillible, stderr is piped {THIS_IS_A_BUG}"));
let pid = Pid::from_raw( let pid = Pid::from_raw(
process process
@@ -392,10 +385,7 @@ where
let filesystem = self.filesystem.clone(); let filesystem = self.filesystem.clone();
let log_path = self.log_path.clone(); let log_path = self.log_path.clone();
self.log_writing_task self.log_writing_task.write().await.replace(tokio::spawn(async move {
.write()
.await
.replace(tokio::spawn(async move {
loop { loop {
while let Some(Ok(data)) = rx.recv().await { while let Some(Ok(data)) = rx.recv().await {
// TODO: find a better way instead of ignoring error ? // TODO: find a better way instead of ignoring error ?
@@ -464,9 +454,7 @@ where
.process_handle .process_handle
.write() .write()
.map_err(|_e| ProviderError::FailedToAcquireLock(self.name.clone()))?; .map_err(|_e| ProviderError::FailedToAcquireLock(self.name.clone()))?;
guard guard.take().ok_or_else(|| anyhow!("no process was attached for the node"))?
.take()
.ok_or_else(|| anyhow!("no process was attached for the node"))?
}; };
match process_handle { match process_handle {
@@ -532,11 +520,7 @@ where
} }
fn path_in_node(&self, file: &Path) -> PathBuf { fn path_in_node(&self, file: &Path) -> PathBuf {
let full_path = format!( let full_path = format!("{}/{}", self.base_dir.to_string_lossy(), file.to_string_lossy());
"{}/{}",
self.base_dir.to_string_lossy(),
file.to_string_lossy()
);
PathBuf::from(full_path) PathBuf::from(full_path)
} }
@@ -569,10 +553,7 @@ where
if result.status.success() { if result.status.success() {
Ok(Ok(String::from_utf8_lossy(&result.stdout).to_string())) Ok(Ok(String::from_utf8_lossy(&result.stdout).to_string()))
} else { } else {
Ok(Err(( Ok(Err((result.status, String::from_utf8_lossy(&result.stderr).to_string())))
result.status,
String::from_utf8_lossy(&result.stderr).to_string(),
)))
} }
} }
@@ -594,16 +575,11 @@ where
"Can't retrieve filename from script with path: {:?}", "Can't retrieve filename from script with path: {:?}",
options.local_script_path options.local_script_path
)))?; )))?;
let remote_script_path = format!( let remote_script_path =
"{}/{}", format!("{}/{}", self.scripts_dir.to_string_lossy(), script_file_name);
self.scripts_dir.to_string_lossy(),
script_file_name
);
// copy and set script's execute permission // copy and set script's execute permission
self.filesystem self.filesystem.copy(local_script_path, &remote_script_path).await?;
.copy(local_script_path, &remote_script_path)
.await?;
self.filesystem.set_mode(&remote_script_path, 0o744).await?; self.filesystem.set_mode(&remote_script_path, 0o744).await?;
// execute script // execute script
@@ -627,9 +603,7 @@ where
remote_file_path.to_string_lossy() remote_file_path.to_string_lossy()
)); ));
self.filesystem self.filesystem.copy(local_file_path, &namespaced_remote_file_path).await?;
.copy(local_file_path, &namespaced_remote_file_path)
.await?;
self.run_command( self.run_command(
RunCommandOptions::new("chmod") RunCommandOptions::new("chmod")
@@ -658,9 +632,7 @@ where
remote_file_path.to_string_lossy() remote_file_path.to_string_lossy()
)); ));
self.filesystem self.filesystem.copy(namespaced_remote_file_path, local_file_path).await?;
.copy(namespaced_remote_file_path, local_file_path)
.await?;
Ok(()) Ok(())
} }
@@ -88,10 +88,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -109,10 +106,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -132,10 +126,7 @@ where
) )
.await?; .await?;
self.namespaces self.namespaces.write().await.insert(namespace.name().to_string(), namespace.clone());
.write()
.await
.insert(namespace.name().to_string(), namespace.clone());
Ok(namespace) Ok(namespace)
} }
@@ -44,21 +44,16 @@ pub async fn extract_execution_result(
pub fn extract_namespace_info( pub fn extract_namespace_info(
json_value: &serde_json::Value, json_value: &serde_json::Value,
) -> Result<(PathBuf, String), ProviderError> { ) -> Result<(PathBuf, String), ProviderError> {
let base_dir = json_value let base_dir =
.get("local_base_dir") json_value.get("local_base_dir").and_then(|v| v.as_str()).map(PathBuf::from).ok_or(
.and_then(|v| v.as_str()) ProviderError::InvalidConfig(
.map(PathBuf::from)
.ok_or(ProviderError::InvalidConfig(
"`field local_base_dir` is missing from zombie.json".to_string(), "`field local_base_dir` is missing from zombie.json".to_string(),
))?; ),
)?;
let name = let name = json_value.get("ns").and_then(|v| v.as_str()).ok_or(
json_value ProviderError::InvalidConfig("field `ns` is missing from zombie.json".to_string()),
.get("ns") )?;
.and_then(|v| v.as_str())
.ok_or(ProviderError::InvalidConfig(
"field `ns` is missing from zombie.json".to_string(),
))?;
Ok((base_dir, name.to_string())) Ok((base_dir, name.to_string()))
} }
@@ -126,10 +126,7 @@ impl SpawnNodeOptions {
P: AsRef<Path>, P: AsRef<Path>,
I: IntoIterator<Item = P>, I: IntoIterator<Item = P>,
{ {
self.created_paths = created_paths self.created_paths = created_paths.into_iter().map(|path| path.as_ref().into()).collect();
.into_iter()
.map(|path| path.as_ref().into())
.collect();
self self
} }
@@ -264,11 +261,7 @@ impl RunCommandOptions {
where where
S: AsRef<str>, S: AsRef<str>,
{ {
Self { Self { program: program.as_ref().to_string(), args: vec![], env: vec![] }
program: program.as_ref().to_string(),
args: vec![],
env: vec![],
}
} }
pub fn args<S, I>(mut self, args: I) -> Self pub fn args<S, I>(mut self, args: I) -> Self
@@ -304,11 +297,7 @@ impl RunScriptOptions {
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
Self { Self { local_script_path: local_script_path.as_ref().into(), args: vec![], env: vec![] }
local_script_path: local_script_path.as_ref().into(),
args: vec![],
env: vec![],
}
} }
pub fn args<S, I>(mut self, args: I) -> Self pub fn args<S, I>(mut self, args: I) -> Self
@@ -36,40 +36,25 @@ async fn rococo_local_with_omni_node_and_wasm_runtime() {
// wait 2 blocks // wait 2 blocks
let alice = network.get_node("alice").unwrap(); let alice = network.get_node("alice").unwrap();
assert!(alice assert!(alice.wait_metric(BEST_BLOCK_METRIC, |b| b > 2_f64).await.is_ok());
.wait_metric(BEST_BLOCK_METRIC, |b| b > 2_f64)
.await
.is_ok());
// omni-collator-1 // omni-collator-1
let collator = network.get_node("omni-collator-1").unwrap(); let collator = network.get_node("omni-collator-1").unwrap();
let client = collator let client = collator.wait_client::<subxt::PolkadotConfig>().await.unwrap();
.wait_client::<subxt::PolkadotConfig>()
.await
.unwrap();
// wait 1 blocks // wait 1 blocks
let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1); let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1);
while let Some(block) = blocks.next().await { while let Some(block) = blocks.next().await {
println!( println!("Block (omni-collator-1) #{}", block.unwrap().header().number);
"Block (omni-collator-1) #{}",
block.unwrap().header().number
);
} }
// omni-collator-2 // omni-collator-2
let collator = network.get_node("omni-collator-2").unwrap(); let collator = network.get_node("omni-collator-2").unwrap();
let client = collator let client = collator.wait_client::<subxt::PolkadotConfig>().await.unwrap();
.wait_client::<subxt::PolkadotConfig>()
.await
.unwrap();
// wait 1 blocks // wait 1 blocks
let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1); let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1);
while let Some(block) = blocks.next().await { while let Some(block) = blocks.next().await {
println!( println!("Block (omni-collator-2) #{}", block.unwrap().header().number);
"Block (omni-collator-2) #{}",
block.unwrap().header().number
);
} }
} }
@@ -37,40 +37,25 @@ async fn polkadot_local_with_chain_spec_runtime() {
// wait 2 blocks // wait 2 blocks
let alice = network.get_node("alice").unwrap(); let alice = network.get_node("alice").unwrap();
assert!(alice assert!(alice.wait_metric(BEST_BLOCK_METRIC, |b| b > 2_f64).await.is_ok());
.wait_metric(BEST_BLOCK_METRIC, |b| b > 2_f64)
.await
.is_ok());
// asset-hub-collator-1 // asset-hub-collator-1
let collator = network.get_node("asset-hub-collator-1").unwrap(); let collator = network.get_node("asset-hub-collator-1").unwrap();
let client = collator let client = collator.wait_client::<subxt::PolkadotConfig>().await.unwrap();
.wait_client::<subxt::PolkadotConfig>()
.await
.unwrap();
// wait 1 blocks // wait 1 blocks
let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1); let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1);
while let Some(block) = blocks.next().await { while let Some(block) = blocks.next().await {
println!( println!("Block (asset-hub-collator-1) #{}", block.unwrap().header().number);
"Block (asset-hub-collator-1) #{}",
block.unwrap().header().number
);
} }
// asset-hub-collator-2 // asset-hub-collator-2
let collator = network.get_node("asset-hub-collator-2").unwrap(); let collator = network.get_node("asset-hub-collator-2").unwrap();
let client = collator let client = collator.wait_client::<subxt::PolkadotConfig>().await.unwrap();
.wait_client::<subxt::PolkadotConfig>()
.await
.unwrap();
// wait 1 blocks // wait 1 blocks
let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1); let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(1);
while let Some(block) = blocks.next().await { while let Some(block) = blocks.next().await {
println!( println!("Block (asset-hub-collator-2) #{}", block.unwrap().header().number);
"Block (asset-hub-collator-2) #{}",
block.unwrap().header().number
);
} }
} }
@@ -50,8 +50,5 @@ async fn ci_native_smoke_should_works() {
// Get a ref to the node // Get a ref to the node
let alice = network.get_node("alice").unwrap(); let alice = network.get_node("alice").unwrap();
// wait 10 blocks // wait 10 blocks
alice alice.wait_metric(BEST_BLOCK_METRIC, |x| x > 9_f64).await.unwrap();
.wait_metric(BEST_BLOCK_METRIC, |x| x > 9_f64)
.await
.unwrap();
} }
+10 -38
View File
@@ -29,8 +29,7 @@ fn small_network() -> NetworkConfig {
}) })
}) })
.with_global_settings(|g| { .with_global_settings(|g| {
g.with_base_dir(PathBuf::from("/tmp/zombie-1")) g.with_base_dir(PathBuf::from("/tmp/zombie-1")).with_tear_down_on_failure(false)
.with_tear_down_on_failure(false)
}) })
.build() .build()
.unwrap() .unwrap()
@@ -67,10 +66,7 @@ async fn ci_k8s_basic_functionalities_should_works() {
) )
.unwrap(); .unwrap();
alice alice.wait_log_line_count("*rted #1*", true, 10).await.unwrap();
.wait_log_line_count("*rted #1*", true, 10)
.await
.unwrap();
// check best block through metrics with timeout // check best block through metrics with timeout
assert!(alice assert!(alice
@@ -102,19 +98,13 @@ async fn ci_k8s_basic_functionalities_should_works() {
drop(client); drop(client);
// check best block through metrics // check best block through metrics
let best_block = alice let best_block = alice.reports("block_height{status=\"best\"}").await.unwrap();
.reports("block_height{status=\"best\"}")
.await
.unwrap();
assert!(best_block >= 2.0, "Current best {best_block}"); assert!(best_block >= 2.0, "Current best {best_block}");
// collator // collator
let collator = network.get_node("collator").unwrap(); let collator = network.get_node("collator").unwrap();
let client = collator let client = collator.wait_client::<subxt::PolkadotConfig>().await.unwrap();
.wait_client::<subxt::PolkadotConfig>()
.await
.unwrap();
// wait 3 blocks // wait 3 blocks
let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(3); let mut blocks = client.blocks().subscribe_finalized().await.unwrap().take(3);
@@ -123,55 +113,37 @@ async fn ci_k8s_basic_functionalities_should_works() {
} }
// add node // add node
let opts = AddNodeOptions { let opts = AddNodeOptions { rpc_port: Some(9444), is_validator: true, ..Default::default() };
rpc_port: Some(9444),
is_validator: true,
..Default::default()
};
network.add_node("new1", opts).await.unwrap(); network.add_node("new1", opts).await.unwrap();
// add collator // add collator
let col_opts = AddCollatorOptions { let col_opts = AddCollatorOptions {
command: Some("polkadot-parachain".try_into().unwrap()), command: Some("polkadot-parachain".try_into().unwrap()),
image: Some( image: Some("docker.io/parity/polkadot-parachain:1.7.0".try_into().unwrap()),
"docker.io/parity/polkadot-parachain:1.7.0"
.try_into()
.unwrap(),
),
..Default::default() ..Default::default()
}; };
network network.add_collator("new-col-1", col_opts, 2000).await.unwrap();
.add_collator("new-col-1", col_opts, 2000)
.await
.unwrap();
// pause / resume // pause / resume
let alice = network.get_node("alice").unwrap(); let alice = network.get_node("alice").unwrap();
alice.pause().await.unwrap(); alice.pause().await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
let res_err = alice let res_err = alice.wait_metric_with_timeout(BEST_BLOCK_METRIC, |x| x > 5_f64, 5_u32).await;
.wait_metric_with_timeout(BEST_BLOCK_METRIC, |x| x > 5_f64, 5_u32)
.await;
assert!(res_err.is_err()); assert!(res_err.is_err());
alice.resume().await.unwrap(); alice.resume().await.unwrap();
alice alice.wait_metric_with_timeout(BEST_BLOCK_METRIC, |x| x > 5_f64, 5_u32).await.unwrap();
.wait_metric_with_timeout(BEST_BLOCK_METRIC, |x| x > 5_f64, 5_u32)
.await
.unwrap();
// timeout connecting ws // timeout connecting ws
let collator = network.get_node("collator").unwrap(); let collator = network.get_node("collator").unwrap();
collator.pause().await.unwrap(); collator.pause().await.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
let r = collator let r = collator.wait_client_with_timeout::<subxt::PolkadotConfig>(1_u32).await;
.wait_client_with_timeout::<subxt::PolkadotConfig>(1_u32)
.await;
assert!(r.is_err()); assert!(r.is_err());
// tear down (optional if you don't detach the network) // tear down (optional if you don't detach the network)
@@ -24,10 +24,7 @@ impl InMemoryFile {
where where
C: AsRef<[u8]>, C: AsRef<[u8]>,
{ {
Self::File { Self::File { mode: 0o664, contents: contents.as_ref().to_vec() }
mode: 0o664,
contents: contents.as_ref().to_vec(),
}
} }
pub fn empty() -> Self { pub fn empty() -> Self {
@@ -67,9 +64,7 @@ pub struct InMemoryFileSystem {
impl InMemoryFileSystem { impl InMemoryFileSystem {
pub fn new(files: HashMap<OsString, InMemoryFile>) -> Self { pub fn new(files: HashMap<OsString, InMemoryFile>) -> Self {
Self { Self { files: Arc::new(RwLock::new(files)) }
files: Arc::new(RwLock::new(files)),
}
} }
} }
@@ -94,18 +89,14 @@ impl FileSystem for InMemoryFileSystem {
for path in path.ancestors().skip(1) { for path in path.ancestors().skip(1) {
match self.files.read().await.get(path.as_os_str()) { match self.files.read().await.get(path.as_os_str()) {
Some(InMemoryFile::Directory { .. }) => continue, Some(InMemoryFile::Directory { .. }) => continue,
Some(InMemoryFile::File { .. }) => Err(anyhow!( Some(InMemoryFile::File { .. }) => {
"ancestor {:?} is not a directory", Err(anyhow!("ancestor {:?} is not a directory", path.as_os_str(),))?
path.as_os_str(), },
))?,
None => Err(anyhow!("ancestor {:?} doesn't exists", path.as_os_str(),))?, None => Err(anyhow!("ancestor {:?} doesn't exists", path.as_os_str(),))?,
}; };
} }
self.files self.files.write().await.insert(os_path.to_owned(), InMemoryFile::dir());
.write()
.await
.insert(os_path.to_owned(), InMemoryFile::dir());
Ok(()) Ok(())
} }
@@ -116,20 +107,14 @@ impl FileSystem for InMemoryFileSystem {
{ {
let path = path.as_ref(); let path = path.as_ref();
let mut files = self.files.write().await; let mut files = self.files.write().await;
let ancestors = path let ancestors = path.ancestors().collect::<Vec<&Path>>().into_iter().rev().skip(1);
.ancestors()
.collect::<Vec<&Path>>()
.into_iter()
.rev()
.skip(1);
for path in ancestors { for path in ancestors {
match files.get(path.as_os_str()) { match files.get(path.as_os_str()) {
Some(InMemoryFile::Directory { .. }) => continue, Some(InMemoryFile::Directory { .. }) => continue,
Some(InMemoryFile::File { .. }) => Err(anyhow!( Some(InMemoryFile::File { .. }) => {
"ancestor {:?} is not a directory", Err(anyhow!("ancestor {:?} is not a directory", path.as_os_str().to_owned(),))?
path.as_os_str().to_owned(), },
))?,
None => files.insert(path.as_os_str().to_owned(), InMemoryFile::dir()), None => files.insert(path.as_os_str().to_owned(), InMemoryFile::dir()),
}; };
} }
@@ -175,10 +160,9 @@ impl FileSystem for InMemoryFileSystem {
for path in path.ancestors().skip(1) { for path in path.ancestors().skip(1) {
match files.get(path.as_os_str()) { match files.get(path.as_os_str()) {
Some(InMemoryFile::Directory { .. }) => continue, Some(InMemoryFile::Directory { .. }) => continue,
Some(InMemoryFile::File { .. }) => Err(anyhow!( Some(InMemoryFile::File { .. }) => {
"ancestor {:?} is not a directory", Err(anyhow!("ancestor {:?} is not a directory", path.as_os_str()))?
path.as_os_str() },
))?,
None => Err(anyhow!("ancestor {:?} doesn't exists", path.as_os_str()))?, None => Err(anyhow!("ancestor {:?} doesn't exists", path.as_os_str()))?,
}; };
} }
@@ -246,10 +230,7 @@ impl FileSystem for InMemoryFileSystem {
where where
P: AsRef<Path> + Send, P: AsRef<Path> + Send,
{ {
self.files self.files.read().await.contains_key(path.as_ref().as_os_str())
.read()
.await
.contains_key(path.as_ref().as_os_str())
} }
} }
@@ -311,10 +292,7 @@ mod tests {
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
(OsString::from_str("/path").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path").unwrap(), InMemoryFile::dir()),
(OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/path/to/my").unwrap(), InMemoryFile::dir()),
OsString::from_str("/path/to/my").unwrap(),
InMemoryFile::dir(),
),
])); ]));
fs.create_dir("/path/to/my/dir").await.unwrap(); fs.create_dir("/path/to/my/dir").await.unwrap();
@@ -350,10 +328,7 @@ mod tests {
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
(OsString::from_str("/path").unwrap(), InMemoryFile::empty()), (OsString::from_str("/path").unwrap(), InMemoryFile::empty()),
(OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/path/to/my").unwrap(), InMemoryFile::dir()),
OsString::from_str("/path/to/my").unwrap(),
InMemoryFile::dir(),
),
])); ]));
let err = fs.create_dir("/path/to/my/dir").await.unwrap_err(); let err = fs.create_dir("/path/to/my/dir").await.unwrap_err();
@@ -525,10 +500,7 @@ mod tests {
let err = fs.read_to_string("/myfile").await.unwrap_err(); let err = fs.read_to_string("/myfile").await.unwrap_err();
assert_eq!( assert_eq!(err.to_string(), "invalid utf-8 encoding for file \"/myfile\"");
err.to_string(),
"invalid utf-8 encoding for file \"/myfile\""
);
} }
#[tokio::test] #[tokio::test]
@@ -554,10 +526,7 @@ mod tests {
async fn write_should_overwrite_file_content_if_file_exists() { async fn write_should_overwrite_file_content_if_file_exists() {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(),
InMemoryFile::file("my file content"),
),
])); ]));
fs.write("/myfile", "my new file content").await.unwrap(); fs.write("/myfile", "my new file content").await.unwrap();
@@ -592,10 +561,7 @@ mod tests {
(OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()),
])); ]));
let err = fs let err = fs.write("/path/to/myfile", "my file content").await.unwrap_err();
.write("/path/to/myfile", "my file content")
.await
.unwrap_err();
assert_eq!(fs.files.read().await.len(), 2); assert_eq!(fs.files.read().await.len(), 2);
assert_eq!(err.to_string(), "ancestor \"/path\" doesn't exists"); assert_eq!(err.to_string(), "ancestor \"/path\" doesn't exists");
@@ -609,10 +575,7 @@ mod tests {
(OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()),
])); ]));
let err = fs let err = fs.write("/path/to/myfile", "my file content").await.unwrap_err();
.write("/path/to/myfile", "my file content")
.await
.unwrap_err();
assert_eq!(fs.files.read().await.len(), 3); assert_eq!(fs.files.read().await.len(), 3);
assert_eq!(err.to_string(), "ancestor \"/path\" is not a directory"); assert_eq!(err.to_string(), "ancestor \"/path\" is not a directory");
@@ -622,15 +585,10 @@ mod tests {
async fn append_should_update_file_content_if_file_exists() { async fn append_should_update_file_content_if_file_exists() {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(),
InMemoryFile::file("my file content"),
),
])); ]));
fs.append("/myfile", " has been updated with new things") fs.append("/myfile", " has been updated with new things").await.unwrap();
.await
.unwrap();
assert_eq!(fs.files.read().await.len(), 2); assert_eq!(fs.files.read().await.len(), 2);
assert!(matches!( assert!(matches!(
@@ -680,10 +638,7 @@ mod tests {
(OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()),
])); ]));
let err = fs let err = fs.append("/path/to/myfile", "my file content").await.unwrap_err();
.append("/path/to/myfile", "my file content")
.await
.unwrap_err();
assert_eq!(fs.files.read().await.len(), 2); assert_eq!(fs.files.read().await.len(), 2);
assert_eq!(err.to_string(), "ancestor \"/path\" doesn't exists"); assert_eq!(err.to_string(), "ancestor \"/path\" doesn't exists");
@@ -697,10 +652,7 @@ mod tests {
(OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()), (OsString::from_str("/path/to").unwrap(), InMemoryFile::dir()),
])); ]));
let err = fs let err = fs.append("/path/to/myfile", "my file content").await.unwrap_err();
.append("/path/to/myfile", "my file content")
.await
.unwrap_err();
assert_eq!(fs.files.read().await.len(), 3); assert_eq!(fs.files.read().await.len(), 3);
assert_eq!(err.to_string(), "ancestor \"/path\" is not a directory"); assert_eq!(err.to_string(), "ancestor \"/path\" is not a directory");
@@ -710,10 +662,7 @@ mod tests {
async fn copy_should_creates_new_destination_file_if_it_doesnt_exists() { async fn copy_should_creates_new_destination_file_if_it_doesnt_exists() {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(),
InMemoryFile::file("my file content"),
),
])); ]));
fs.copy("/myfile", "/myfilecopy").await.unwrap(); fs.copy("/myfile", "/myfilecopy").await.unwrap();
@@ -728,14 +677,8 @@ mod tests {
async fn copy_should_updates_the_file_content_of_the_destination_file_if_it_already_exists() { async fn copy_should_updates_the_file_content_of_the_destination_file_if_it_already_exists() {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my new file content")),
OsString::from_str("/myfile").unwrap(), (OsString::from_str("/myfilecopy").unwrap(), InMemoryFile::file("my file content")),
InMemoryFile::file("my new file content"),
),
(
OsString::from_str("/myfilecopy").unwrap(),
InMemoryFile::file("my file content"),
),
])); ]));
fs.copy("/myfile", "/myfilecopy").await.unwrap(); fs.copy("/myfile", "/myfilecopy").await.unwrap();
@@ -774,14 +717,8 @@ mod tests {
async fn copy_should_returns_an_error_if_destination_file_is_a_directory() { async fn copy_should_returns_an_error_if_destination_file_is_a_directory() {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(), (OsString::from_str("/myfilecopy").unwrap(), InMemoryFile::dir()),
InMemoryFile::file("my file content"),
),
(
OsString::from_str("/myfilecopy").unwrap(),
InMemoryFile::dir(),
),
])); ]));
let err = fs.copy("/myfile", "/myfilecopy").await.unwrap_err(); let err = fs.copy("/myfile", "/myfilecopy").await.unwrap_err();
@@ -794,10 +731,7 @@ mod tests {
) { ) {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(),
InMemoryFile::file("my file content"),
),
])); ]));
let err = fs.copy("/myfile", "/somedir/myfilecopy").await.unwrap_err(); let err = fs.copy("/myfile", "/somedir/myfilecopy").await.unwrap_err();
@@ -811,14 +745,8 @@ mod tests {
) { ) {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(), (OsString::from_str("/mypath").unwrap(), InMemoryFile::empty()),
InMemoryFile::file("my file content"),
),
(
OsString::from_str("/mypath").unwrap(),
InMemoryFile::empty(),
),
])); ]));
let err = fs.copy("/myfile", "/mypath/myfilecopy").await.unwrap_err(); let err = fs.copy("/myfile", "/mypath/myfilecopy").await.unwrap_err();
@@ -831,10 +759,7 @@ mod tests {
async fn set_mode_should_update_the_file_mode_at_path() { async fn set_mode_should_update_the_file_mode_at_path() {
let fs = InMemoryFileSystem::new(HashMap::from([ let fs = InMemoryFileSystem::new(HashMap::from([
(OsString::from_str("/").unwrap(), InMemoryFile::dir()), (OsString::from_str("/").unwrap(), InMemoryFile::dir()),
( (OsString::from_str("/myfile").unwrap(), InMemoryFile::file("my file content")),
OsString::from_str("/myfile").unwrap(),
InMemoryFile::file("my file content"),
),
])); ]));
assert!( assert!(
matches!(fs.files.read().await.get(&OsString::from_str("/myfile").unwrap()).unwrap(), InMemoryFile::File { mode, .. } if *mode == 0o664) matches!(fs.files.read().await.get(&OsString::from_str("/myfile").unwrap()).unwrap(), InMemoryFile::File { mode, .. } if *mode == 0o664)
+5 -18
View File
@@ -59,9 +59,7 @@ impl FileSystem for LocalFileSystem {
.await .await
.map_err(Into::<FileSystemError>::into)?; .map_err(Into::<FileSystemError>::into)?;
file.write_all(contents) file.write_all(contents).await.map_err(Into::<FileSystemError>::into)?;
.await
.map_err(Into::<FileSystemError>::into)?;
file.flush().await.and(Ok(())).map_err(Into::into) file.flush().await.and(Ok(())).map_err(Into::into)
} }
@@ -71,19 +69,14 @@ impl FileSystem for LocalFileSystem {
P1: AsRef<Path> + Send, P1: AsRef<Path> + Send,
P2: AsRef<Path> + Send, P2: AsRef<Path> + Send,
{ {
tokio::fs::copy(from, to) tokio::fs::copy(from, to).await.and(Ok(())).map_err(Into::into)
.await
.and(Ok(()))
.map_err(Into::into)
} }
async fn set_mode<P>(&self, path: P, mode: u32) -> FileSystemResult<()> async fn set_mode<P>(&self, path: P, mode: u32) -> FileSystemResult<()>
where where
P: AsRef<Path> + Send, P: AsRef<Path> + Send,
{ {
tokio::fs::set_permissions(path, Permissions::from_mode(mode)) tokio::fs::set_permissions(path, Permissions::from_mode(mode)).await.map_err(Into::into)
.await
.map_err(Into::into)
} }
async fn exists<P>(&self, path: P) -> bool async fn exists<P>(&self, path: P) -> bool
@@ -351,10 +344,7 @@ mod tests {
fs.set_mode(&path, 0o400).await.unwrap(); fs.set_mode(&path, 0o400).await.unwrap();
assert_eq!( assert_eq!(std::fs::metadata(&path).unwrap().permissions().mode(), FILE_BITS + 0o400);
std::fs::metadata(&path).unwrap().permissions().mode(),
FILE_BITS + 0o400
);
teardown(test_dir); teardown(test_dir);
} }
@@ -368,10 +358,7 @@ mod tests {
fs.set_mode(&path, 0o700).await.unwrap(); fs.set_mode(&path, 0o700).await.unwrap();
assert_eq!( assert_eq!(std::fs::metadata(&path).unwrap().permissions().mode(), DIR_BITS + 0o700);
std::fs::metadata(&path).unwrap().permissions().mode(),
DIR_BITS + 0o700
);
teardown(test_dir); teardown(test_dir);
} }
@@ -78,9 +78,7 @@ pub fn apply_running_network_replacements(text: &str, network: &serde_json::Valu
pub fn get_tokens_to_replace(text: &str) -> HashSet<String> { pub fn get_tokens_to_replace(text: &str) -> HashSet<String> {
let mut tokens = HashSet::new(); let mut tokens = HashSet::new();
TOKEN_PLACEHOLDER TOKEN_PLACEHOLDER.captures_iter(text).for_each(|caps: Captures| {
.captures_iter(text)
.for_each(|caps: Captures| {
tokens.insert(caps[1].to_string()); tokens.insert(caps[1].to_string());
}); });
+14 -21
View File
@@ -1,26 +1,19 @@
# https://rust-lang.github.io/rustfmt/?version=v1.7.0 # Pezkuwi ZombieNet SDK - Stable Rustfmt Configuration
# Only stable features for compatibility with CI
# general # Basic (stable)
indent_style = "Block" hard_tabs = true
max_width = 100
use_small_heuristics = "Max"
# rewriting # Imports (stable)
condense_wildcard_suffixes = true reorder_imports = true
reorder_modules = true
# Consistency (stable)
newline_style = "Unix"
# Misc (stable)
match_block_trailing_comma = true match_block_trailing_comma = true
use_field_init_shorthand = true use_field_init_shorthand = true
use_try_shorthand = true use_try_shorthand = true
# normalization
normalize_comments = true
normalize_doc_attributes = true
# reordering
reorder_impl_items = true
reorder_imports = true
reorder_modules = true
imports_granularity = "Crate"
group_imports = "StdExternalCrate"
# additional formating
format_code_in_doc_comments = true
format_macro_matchers = true
format_macro_bodies = true