diff --git a/core/node/node_framework/src/service/mod.rs b/core/node/node_framework/src/service/mod.rs index 0f182791faec..38902c254613 100644 --- a/core/node/node_framework/src/service/mod.rs +++ b/core/node/node_framework/src/service/mod.rs @@ -38,8 +38,19 @@ impl ZkStackServiceBuilder { /// Adds a wiring layer. /// During the [`run`](ZkStackService::run) call the service will invoke /// `wire` method of every layer in the order they were added. + /// + /// This method may be invoked multiple times with the same layer type, but the + /// layer will only be stored once (meaning that 2nd attempt to add the same layer will be ignored). + /// This may be useful if the same layer is a prerequisite for multiple other layers: it is safe + /// to add it multiple times, and it will only be wired once. pub fn add_layer(&mut self, layer: T) -> &mut Self { - self.layers.push(Box::new(layer)); + if !self + .layers + .iter() + .any(|existing_layer| existing_layer.layer_name() == layer.layer_name()) + { + self.layers.push(Box::new(layer)); + } self } diff --git a/core/node/node_framework/src/service/tests.rs b/core/node/node_framework/src/service/tests.rs index b31e761854c2..13a005863c53 100644 --- a/core/node/node_framework/src/service/tests.rs +++ b/core/node/node_framework/src/service/tests.rs @@ -24,12 +24,14 @@ fn test_new_with_nested_runtime() { } #[derive(Debug)] -struct DefaultLayer; +struct DefaultLayer { + name: &'static str, +} #[async_trait::async_trait] impl WiringLayer for DefaultLayer { fn layer_name(&self) -> &'static str { - "default_layer" + self.name } async fn wire(self: Box, mut _node: ServiceContext<'_>) -> Result<(), WiringError> { @@ -37,13 +39,17 @@ impl WiringLayer for DefaultLayer { } } -// `ZkStack` Service's `add_layer()` method has to add multiple layers into `self.layers`. +// `add_layer` should add multiple layers. #[test] fn test_add_layer() { let mut zk_stack_service = ZkStackServiceBuilder::new(); zk_stack_service - .add_layer(DefaultLayer) - .add_layer(DefaultLayer); + .add_layer(DefaultLayer { + name: "first_layer", + }) + .add_layer(DefaultLayer { + name: "second_layer", + }); let actual_layers_len = zk_stack_service.layers.len(); assert_eq!( 2, actual_layers_len, @@ -51,6 +57,24 @@ fn test_add_layer() { ); } +// `add_layer` should ignore already added layers. +#[test] +fn test_layers_are_unique() { + let mut zk_stack_service = ZkStackServiceBuilder::new(); + zk_stack_service + .add_layer(DefaultLayer { + name: "default_layer", + }) + .add_layer(DefaultLayer { + name: "default_layer", + }); + let actual_layers_len = zk_stack_service.layers.len(); + assert_eq!( + 1, actual_layers_len, + "Incorrect number of layers in the service" + ); +} + // `ZkStack` Service's `run()` method has to return error if there is no tasks added. #[test] fn test_run_with_no_tasks() {