Repository: tangle-network/gadget (language: rust)

Issue:
[TASK] Add prometheus monitoring and metrics 
# Overview
We should identify generic metrics that can be added to this repo such as:
- the # of jobs received/completed
- time of job completion from submission or other steps
- peer connectivity


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/validate_pr.yml b/.github/workflows/validate_pr.yml
index b6fbf6237..bf9332ccb 100644
--- a/.github/workflows/validate_pr.yml
+++ b/.github/workflows/validate_pr.yml
@@ -3,6 +3,8 @@ name: Validate PR
 on:
   pull_request:
     branches: [main]
+  push:
+    branches: [main]
 
 concurrency:
   group: rust-validation-${{ github.head_ref }}
diff --git a/Cargo.lock b/Cargo.lock
index 4a5fa3644..0f78d9b18 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -791,16 +791,6 @@ version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
-[[package]]
-name = "atomic-write-file"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
-dependencies = [
- "nix 0.27.1",
- "rand 0.8.5",
-]
-
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -3052,12 +3042,13 @@ dependencies = [
 
 [[package]]
 name = "flume"
-version = "0.11.0"
+version = "0.10.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
+checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
 dependencies = [
  "futures-core",
  "futures-sink",
+ "pin-project",
  "spin 0.9.8",
 ]
 
@@ -3526,6 +3517,7 @@ dependencies = [
  "futures-util",
  "gadget-core",
  "hex",
+ "lazy_static",
  "linked-hash-map",
  "log",
  "pallet-jobs-rpc-runtime-api",
@@ -3543,6 +3535,7 @@ dependencies = [
  "sp-core",
  "sp-runtime",
  "sqlx",
+ "substrate-prometheus-endpoint",
  "subxt-signer",
  "tangle-primitives",
  "tokio",
@@ -4976,9 +4969,9 @@ dependencies = [
 
 [[package]]
 name = "libsqlite3-sys"
-version = "0.27.0"
+version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
+checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
 dependencies = [
  "cc",
  "pkg-config",
@@ -5577,17 +5570,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "nix"
-version = "0.27.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
-dependencies = [
- "bitflags 2.4.2",
- "cfg-if",
- "libc",
-]
-
 [[package]]
 name = "no-std-net"
 version = "0.6.0"
@@ -7498,7 +7480,7 @@ dependencies = [
  "log",
  "netlink-packet-route",
  "netlink-proto",
- "nix 0.24.3",
+ "nix",
  "thiserror",
  "tokio",
 ]
@@ -9375,9 +9357,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
+checksum = "8e58421b6bc416714d5115a2ca953718f6c621a51b68e4f4922aea5a4391a721"
 dependencies = [
  "sqlx-core",
  "sqlx-macros",
@@ -9388,9 +9370,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-core"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
+checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53"
 dependencies = [
  "ahash 0.8.8",
  "atoi",
@@ -9426,14 +9408,14 @@ dependencies = [
  "tokio-stream",
  "tracing",
  "url",
- "webpki-roots 0.25.4",
+ "webpki-roots 0.24.0",
 ]
 
 [[package]]
 name = "sqlx-macros"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
+checksum = "208e3165167afd7f3881b16c1ef3f2af69fa75980897aac8874a0696516d12c2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9444,11 +9426,10 @@ dependencies = [
 
 [[package]]
 name = "sqlx-macros-core"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
+checksum = "8a4a8336d278c62231d87f24e8a7a74898156e34c1c18942857be2acb29c7dfc"
 dependencies = [
- "atomic-write-file",
  "dotenvy",
  "either",
  "heck 0.4.1",
@@ -9470,9 +9451,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-mysql"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
+checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482"
 dependencies = [
  "atoi",
  "base64 0.21.7",
@@ -9512,9 +9493,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-postgres"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
+checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e"
 dependencies = [
  "atoi",
  "base64 0.21.7",
@@ -9551,9 +9532,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-sqlite"
-version = "0.7.3"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
+checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2"
 dependencies = [
  "atoi",
  "flume",
@@ -9569,7 +9550,6 @@ dependencies = [
  "sqlx-core",
  "tracing",
  "url",
- "urlencoding",
 ]
 
 [[package]]
@@ -10696,12 +10676,6 @@ dependencies = [
  "percent-encoding",
 ]
 
-[[package]]
-name = "urlencoding"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
-
 [[package]]
 name = "uuid"
 version = "1.7.0"
@@ -11442,6 +11416,15 @@ dependencies = [
  "webpki",
 ]
 
+[[package]]
+name = "webpki-roots"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888"
+dependencies = [
+ "rustls-webpki",
+]
+
 [[package]]
 name = "webpki-roots"
 version = "0.25.4"
diff --git a/Cargo.toml b/Cargo.toml
index d32a434da..a5d42cc2a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -130,3 +130,6 @@ k256 = "0.13.2"
 anyhow = "1.0.79"
 libsecp256k1 = "0.7.1"
 rayon = { version = "1.8.0" }
+substrate-prometheus-endpoint = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+lazy_static = "1.4.0"
+sqlx = "=0.7.1"
\ No newline at end of file
diff --git a/gadget-common/Cargo.toml b/gadget-common/Cargo.toml
index 67d6bacc0..a753b3206 100644
--- a/gadget-common/Cargo.toml
+++ b/gadget-common/Cargo.toml
@@ -38,7 +38,9 @@ anyhow = { workspace = true }
 futures = { workspace = true }
 round-based = { workspace = true }
 sp-api = { workspace = true }
-sqlx = { version = "0.7.3", features = ["runtime-tokio-rustls", "sqlite"] }
+sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite"] }
+substrate-prometheus-endpoint = { workspace = true }
+lazy_static = { workspace = true }
 
 frame-support = { workspace = true }
 sc-network = { workspace = true }
diff --git a/gadget-common/src/config.rs b/gadget-common/src/config.rs
index 3626c2cbd..9b95a9cf1 100644
--- a/gadget-common/src/config.rs
+++ b/gadget-common/src/config.rs
@@ -3,6 +3,7 @@ pub use crate::client::{AccountId, ClientWithApi};
 pub use crate::debug_logger::DebugLogger;
 pub use crate::gadget::network::Network;
 pub use crate::gadget::GadgetProtocol;
+pub use crate::prometheus::PrometheusConfig;
 use async_trait::async_trait;
 pub use pallet_jobs_rpc_runtime_api::JobsApi;
 pub use sc_client_api::Backend;
@@ -29,6 +30,7 @@ where
     fn take_network(&mut self) -> Self::Network;
     fn take_protocol(&mut self) -> Self::Protocol;
     fn take_client(&mut self) -> <Self::ProtocolSpecificConfiguration as NetworkAndProtocolSetup>::Client;
+    fn prometheus_config(&self) -> PrometheusConfig;
 
     async fn build(&self) -> Result<Self, crate::Error> {
         let jobs_client = self.params().build_jobs_client().await?;
@@ -37,8 +39,10 @@ where
         let params = self.params().clone();
         let pallet_tx = self.pallet_tx();
         let logger = self.logger();
+        let prometheus_config = self.prometheus_config();
+
         Ok(Self::new(
-            network, client, protocol, params, pallet_tx, logger,
+            network, client, protocol, params, pallet_tx, logger, prometheus_config,
         ))
     }
 
@@ -49,6 +53,7 @@ where
         params: Self::ProtocolSpecificConfiguration,
         pallet_tx: Arc<dyn PalletSubmitter>,
         logger: DebugLogger,
+        prometheus_config: PrometheusConfig,
     ) -> Self;
 
     fn pallet_tx(&self) -> Arc<dyn PalletSubmitter> {
diff --git a/gadget-common/src/full_protocol.rs b/gadget-common/src/full_protocol.rs
index 36a3bad22..fe30f2ff4 100644
--- a/gadget-common/src/full_protocol.rs
+++ b/gadget-common/src/full_protocol.rs
@@ -6,6 +6,7 @@ use crate::gadget::message::GadgetProtocolMessage;
 use crate::gadget::work_manager::WorkManager;
 use crate::gadget::{JobInitMetadata, WorkManagerConfig};
 use crate::keystore::{ECDSAKeyStore, KeystoreBackend};
+use crate::prometheus::PrometheusConfig;
 use crate::protocol::AsyncProtocol;
 use crate::Error;
 use async_trait::async_trait;
@@ -41,6 +42,7 @@ where
         logger: DebugLogger,
         account_id: AccountId,
         key_store: ECDSAKeyStore<Self::KeystoreBackend>,
+        prometheus_config: PrometheusConfig,
     ) -> Result<Self, Error>;
     async fn generate_protocol_from(
         &self,
@@ -221,13 +223,16 @@ where
     <T::Client as ProvideRuntimeApi<T::Block>>::Api: JobsApiForGadget<T::Block>,
 {
     async fn next_message(&self) -> Option<<WorkManager as WorkManagerInterface>::ProtocolMessage> {
-        T::network(self).next_message().await
+        let message = T::network(self).next_message().await?;
+        crate::prometheus::BYTES_RECEIVED.inc_by(message.payload.len() as u64);
+        Some(message)
     }
 
     async fn send_message(
         &self,
         message: <WorkManager as WorkManagerInterface>::ProtocolMessage,
     ) -> Result<(), Error> {
+        crate::prometheus::BYTES_SENT.inc_by(message.payload.len() as u64);
         T::network(self).send_message(message).await
     }
 }
@@ -253,5 +258,6 @@ pub struct NodeInput<
     pub keystore: ECDSAKeyStore<KBE>,
     pub node_index: usize,
     pub additional_params: D,
+    pub prometheus_config: PrometheusConfig,
     pub _pd: PhantomData<(B, BE)>,
 }
diff --git a/gadget-common/src/lib.rs b/gadget-common/src/lib.rs
index cf5869c28..d4bcdef21 100644
--- a/gadget-common/src/lib.rs
+++ b/gadget-common/src/lib.rs
@@ -2,6 +2,7 @@ use crate::client::{AccountId, ClientWithApi, JobsApiForGadget};
 use crate::config::{NetworkAndProtocolSetup, ProtocolConfig};
 use crate::gadget::work_manager::WorkManager;
 use crate::gadget::{GadgetProtocol, Module};
+use crate::prelude::PrometheusConfig;
 use gadget::network::Network;
 use gadget_core::gadget::manager::{AbstractGadget, GadgetError, GadgetManager};
 use gadget_core::gadget::substrate::{Client, SubstrateGadget};
@@ -51,6 +52,7 @@ pub mod gadget;
 pub mod helpers;
 pub mod keystore;
 pub mod locks;
+pub mod prometheus;
 pub mod protocol;
 #[derive(Debug)]
 pub enum Error {
@@ -71,6 +73,7 @@ pub enum Error {
     PeerNotFound { id: AccountId },
     JoinError { err: JoinError },
     ParticipantNotSelected { id: AccountId, reason: String },
+    PrometheusError { err: String },
 }
 
 impl Display for Error {
@@ -97,6 +100,8 @@ where
     let network = protocol_config.take_network();
     let protocol = protocol_config.take_protocol();
 
+    let prometheus_config = protocol_config.prometheus_config();
+
     // Before running, wait for the first finality notification we receive
     let latest_finality_notification =
         get_latest_finality_notification_from_client(&client).await?;
@@ -120,6 +125,16 @@ where
             .map_err(|err| Error::GadgetManagerError { err })
     };
 
+    if let Err(err) = prometheus::setup(prometheus_config.clone()).await {
+        protocol_config
+            .logger()
+            .warn(format!("Error setting up prometheus: {err:?}"));
+    } else if let PrometheusConfig::Enabled { bind_addr } = prometheus_config {
+        protocol_config
+            .logger()
+            .info(format!("Prometheus enabled on {bind_addr}"));
+    }
+
     // Run both the network and the gadget together
     tokio::try_join!(network_future, gadget_future).map(|_| ())
 }
@@ -192,6 +207,7 @@ macro_rules! generate_setup_and_run_command {
                     node_input.logger.clone(),
                     node_input.account_id,
                     node_input.keystore,
+                    node_input.prometheus_config,
                 )
                 .await
                 {
@@ -209,6 +225,7 @@ macro_rules! generate_setup_and_run_command {
             logger: DebugLogger,
             account_id: AccountId,
             key_store: ECDSAKeyStore<KBE>,
+            prometheus_config: $crate::prometheus::PrometheusConfig,
         ) -> Result<(), Error>
         where
             <C as ProvideRuntimeApi<B>>::Api: JobsApiForGadget<B>,
@@ -217,7 +234,7 @@ macro_rules! generate_setup_and_run_command {
             let futures = futures::stream::FuturesUnordered::new();
 
             $(
-                let config = crate::$config::new(client.pop().expect("Not enough clients"), pallet_tx.clone(), network.pop().expect("Not enough networks"), logger.clone(), account_id.clone(), key_store.clone()).await?;
+                let config = crate::$config::new(client.pop().expect("Not enough clients"), pallet_tx.clone(), network.pop().expect("Not enough networks"), logger.clone(), account_id.clone(), key_store.clone(), prometheus_config.clone()).await?;
                 futures.push(Box::pin(config.execute()) as std::pin::Pin<Box<dyn SendFuture<'static, Result<(), gadget_common::Error>>>>);
             )*
 
@@ -246,6 +263,7 @@ macro_rules! generate_protocol {
             account_id: AccountId,
             key_store: ECDSAKeyStore<KBE>,
             jobs_client: Arc<Mutex<Option<JobsClient<B, BE, C>>>>,
+            prometheus_config: $crate::prometheus::PrometheusConfig,
             _pd: std::marker::PhantomData<(B, BE)>,
         }
 
@@ -275,6 +293,7 @@ macro_rules! generate_protocol {
                 logger: DebugLogger,
                 account_id: AccountId,
                 key_store: ECDSAKeyStore<Self::KeystoreBackend>,
+                prometheus_config: $crate::prometheus::PrometheusConfig,
             ) -> Result<Self, Error> {
                 Ok(Self {
                     pallet_tx,
@@ -283,6 +302,7 @@ macro_rules! generate_protocol {
                     network,
                     account_id,
                     key_store,
+                    prometheus_config,
                     jobs_client: Arc::new(parking_lot::Mutex::new(None)),
                     _pd: std::marker::PhantomData,
                 })
diff --git a/gadget-common/src/prometheus.rs b/gadget-common/src/prometheus.rs
new file mode 100644
index 000000000..41dd12402
--- /dev/null
+++ b/gadget-common/src/prometheus.rs
@@ -0,0 +1,58 @@
+use lazy_static::lazy_static;
+use std::net::SocketAddr;
+use std::str::FromStr;
+use std::sync::atomic::AtomicBool;
+use substrate_prometheus_endpoint::prometheus::{IntCounter, Registry};
+
+lazy_static! {
+    pub static ref REGISTRY: Registry = Registry::new();
+    pub static ref BYTES_RECEIVED: IntCounter =
+        IntCounter::new("bytes_received", "Bytes Received").expect("metric can be created");
+    pub static ref BYTES_SENT: IntCounter =
+        IntCounter::new("bytes_sent", "Bytes Sent").expect("metric can be created");
+}
+
+#[derive(Debug, Clone)]
+pub enum PrometheusConfig {
+    Enabled { bind_addr: SocketAddr },
+    Disabled,
+}
+
+impl Default for PrometheusConfig {
+    fn default() -> Self {
+        Self::Enabled {
+            bind_addr: SocketAddr::from_str("0.0.0.0:9615").unwrap(),
+        }
+    }
+}
+
+pub async fn setup(config: PrometheusConfig) -> Result<(), crate::Error> {
+    if let PrometheusConfig::Enabled { bind_addr } = config {
+        static HAS_REGISTERED: AtomicBool = AtomicBool::new(false);
+        if HAS_REGISTERED.load(std::sync::atomic::Ordering::SeqCst) {
+            return Ok(());
+        }
+
+        HAS_REGISTERED.store(true, std::sync::atomic::Ordering::SeqCst);
+
+        substrate_prometheus_endpoint::register(BYTES_RECEIVED.clone(), &REGISTRY).map_err(
+            |err| crate::Error::PrometheusError {
+                err: err.to_string(),
+            },
+        )?;
+
+        substrate_prometheus_endpoint::register(BYTES_SENT.clone(), &REGISTRY).map_err(|err| {
+            crate::Error::PrometheusError {
+                err: err.to_string(),
+            }
+        })?;
+
+        substrate_prometheus_endpoint::init_prometheus(bind_addr, REGISTRY.clone())
+            .await
+            .map_err(|err| crate::Error::PrometheusError {
+                err: err.to_string(),
+            })?;
+    }
+
+    Ok(())
+}
diff --git a/protocol-macros/src/lib.rs b/protocol-macros/src/lib.rs
index fbc15cff2..c64b22cc4 100644
--- a/protocol-macros/src/lib.rs
+++ b/protocol-macros/src/lib.rs
@@ -111,6 +111,7 @@ pub fn protocol(_args: TokenStream, input: TokenStream) -> TokenStream {
             pub params: #struct_ident<#generics_token_stream>,
             pub pallet_tx: Arc<dyn gadget_common::client::PalletSubmitter>,
             pub logger: gadget_common::config::DebugLogger,
+            pub prometheus_config: gadget_common::prometheus::PrometheusConfig,
             _pd: std::marker::PhantomData<(B, BE)>,
         }
 
@@ -121,7 +122,7 @@ pub fn protocol(_args: TokenStream, input: TokenStream) -> TokenStream {
             type Protocol = <Self::ProtocolSpecificConfiguration as gadget_common::config::NetworkAndProtocolSetup>::Protocol;
             type ProtocolSpecificConfiguration = #struct_ident <#generics_token_stream>;
 
-            fn new(network: Self::Network, client: <Self::ProtocolSpecificConfiguration as gadget_common::config::NetworkAndProtocolSetup>::Client, protocol: Self::Protocol, params: Self::ProtocolSpecificConfiguration, pallet_tx: Arc<dyn gadget_common::client::PalletSubmitter>, logger: DebugLogger) -> Self {
+            fn new(network: Self::Network, client: <Self::ProtocolSpecificConfiguration as gadget_common::config::NetworkAndProtocolSetup>::Client, protocol: Self::Protocol, params: Self::ProtocolSpecificConfiguration, pallet_tx: Arc<dyn gadget_common::client::PalletSubmitter>, logger: DebugLogger, prometheus_config: gadget_common::prometheus::PrometheusConfig) -> Self {
                 Self {
                     network: Some(network),
                     client: Some(client),
@@ -129,6 +130,7 @@ pub fn protocol(_args: TokenStream, input: TokenStream) -> TokenStream {
                     params,
                     pallet_tx,
                     logger,
+                    prometheus_config,
                     _pd: std::marker::PhantomData,
                 }
             }
@@ -145,6 +147,10 @@ pub fn protocol(_args: TokenStream, input: TokenStream) -> TokenStream {
                 self.client.take().expect("Client not set")
             }
 
+            fn prometheus_config(&self) -> gadget_common::config::PrometheusConfig {
+                self.prometheus_config.clone()
+            }
+
             fn params(&self) -> &Self::ProtocolSpecificConfiguration {
                 &self.params
             }
@@ -164,6 +170,7 @@ pub fn protocol(_args: TokenStream, input: TokenStream) -> TokenStream {
                     params: self,
                     pallet_tx,
                     logger,
+                    prometheus_config: Default::default(),
                     _pd: std::marker::PhantomData,
                 }
             }
diff --git a/protocols/stub/src/lib.rs b/protocols/stub/src/lib.rs
index 56881da2f..4918f1104 100644
--- a/protocols/stub/src/lib.rs
+++ b/protocols/stub/src/lib.rs
@@ -19,6 +19,7 @@ pub struct StubProtocol<
     network: N,
     account_id: AccountId,
     key_store: ECDSAKeyStore<KBE>,
+    prometheus_config: PrometheusConfig,
     jobs_client: Arc<Mutex<Option<JobsClient<B, BE, C>>>>,
 }
 
@@ -48,6 +49,7 @@ where
         logger: DebugLogger,
         account_id: AccountId,
         key_store: ECDSAKeyStore<Self::KeystoreBackend>,
+        prometheus_config: PrometheusConfig,
     ) -> Result<Self, Error> {
         Ok(Self {
             pallet_tx,
@@ -56,6 +58,7 @@ where
             network,
             account_id,
             key_store,
+            prometheus_config,
             jobs_client: Arc::new(Mutex::new(None)),
         })
     }


Test patch:
diff --git a/protocols/dfns-cggmp21/tests/dfns.rs b/protocols/dfns-cggmp21/tests/dfns.rs
index 1b9febeae..a3287a687 100644
--- a/protocols/dfns-cggmp21/tests/dfns.rs
+++ b/protocols/dfns-cggmp21/tests/dfns.rs
@@ -207,7 +207,13 @@ mod tests {
             let (pallet_tx, key_store) = (node_input.pallet_tx, node_input.keystore);
             logger.info("Starting gadget");
             if let Err(err) = dfns_cggmp21_protocol::run::<_, MockBackend, _, _, _>(
-                clients, pallet_tx, networks, logger, account_id, key_store,
+                clients,
+                pallet_tx,
+                networks,
+                logger,
+                account_id,
+                key_store,
+                Default::default(),
             )
             .await
             {
diff --git a/protocols/zk-saas/tests/zksaas.rs b/protocols/zk-saas/tests/zksaas.rs
index 9ef0ac0a1..f1982b011 100644
--- a/protocols/zk-saas/tests/zksaas.rs
+++ b/protocols/zk-saas/tests/zksaas.rs
@@ -217,6 +217,7 @@ mod tests {
                 logger,
                 node_info.account_id,
                 key_store,
+                Default::default(),
             )
             .await
             {
diff --git a/test-utils/src/mock.rs b/test-utils/src/mock.rs
index 0fb4296c3..50c29c93d 100644
--- a/test-utils/src/mock.rs
+++ b/test-utils/src/mock.rs
@@ -46,6 +46,7 @@ use gadget_common::gadget::network::Network;
 use gadget_common::gadget::work_manager::WorkManager;
 use gadget_common::keystore::{ECDSAKeyStore, InMemoryBackend};
 use gadget_common::locks::TokioMutexExt;
+use gadget_common::prelude::PrometheusConfig;
 use gadget_common::Error;
 use gadget_core::job_manager::{SendFuture, WorkManagerInterface};
 use sp_core::ecdsa;
@@ -549,6 +550,9 @@ pub async fn new_test_ext<
         // Assume all clients/networks share the same keystore for sharing results
         // between phases
         let keystore = ECDSAKeyStore::in_memory(identity_pair);
+
+        let prometheus_config = PrometheusConfig::Disabled;
+
         let input = NodeInput {
             mock_clients,
             mock_networks: networks,
@@ -558,6 +562,7 @@ pub async fn new_test_ext<
             keystore,
             node_index,
             additional_params: additional_params.clone(),
+            prometheus_config,
             _pd: Default::default(),
         };