Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false

[dependencies]
cb-common.workspace = true
cb-metrics.workspace = true

# ethereum
alloy.workspace = true
Expand All @@ -21,6 +22,7 @@ tokio.workspace = true

# telemetry
tracing.workspace = true
prometheus.workspace = true

# crypto
blst.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions crates/signer/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub const GET_PUBKEYS_ENDPOINT_TAG: &str = "get_pubkeys";
pub const GENERATE_PROXY_KEY_ENDPOINT_TAG: &str = "generate_proxy_key";
pub const REQUEST_SIGNATURE_ENDPOINT_TAG: &str = "request_signature";
2 changes: 2 additions & 0 deletions crates/signer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod constants;
pub mod error;
pub mod manager;
mod metrics;
pub mod service;
34 changes: 34 additions & 0 deletions crates/signer/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Metrics for Signer module

use axum::http::Uri;
use cb_common::commit::constants::{
GENERATE_PROXY_KEY_PATH, GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH,
};
use lazy_static::lazy_static;
use prometheus::{register_int_counter_vec_with_registry, IntCounterVec, Registry};

use crate::constants::{
GENERATE_PROXY_KEY_ENDPOINT_TAG, GET_PUBKEYS_ENDPOINT_TAG, REQUEST_SIGNATURE_ENDPOINT_TAG,
};

lazy_static! {
pub static ref SIGNER_METRICS_REGISTRY: Registry =
Registry::new_custom(Some("cb_signer".to_string()), None).unwrap();

/// Status code returned by endpoint
pub static ref SIGNER_STATUS: IntCounterVec = register_int_counter_vec_with_registry!(
"signer_status_code_total",
"HTTP status code returned by signer",
&["http_status_code", "endpoint"],
SIGNER_METRICS_REGISTRY
).unwrap();
}

pub fn uri_to_tag(uri: &Uri) -> &str {
match uri.path() {
GET_PUBKEYS_PATH => GET_PUBKEYS_ENDPOINT_TAG,
GENERATE_PROXY_KEY_PATH => GENERATE_PROXY_KEY_ENDPOINT_TAG,
REQUEST_SIGNATURE_PATH => REQUEST_SIGNATURE_ENDPOINT_TAG,
_ => "unknown endpoint",
}
}
23 changes: 21 additions & 2 deletions crates/signer/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ use cb_common::{
constants::COMMIT_BOOST_VERSION,
types::{Jwt, ModuleId},
};
use cb_metrics::provider::MetricsProvider;
use eyre::{Context, Result};
use headers::{authorization::Bearer, Authorization};
use tokio::{net::TcpListener, sync::RwLock};
use tracing::{debug, error, info, warn};
use uuid::Uuid;

use crate::{error::SignerModuleError, manager::SigningManager};
use crate::{
error::SignerModuleError,
manager::SigningManager,
metrics::{uri_to_tag, SIGNER_METRICS_REGISTRY, SIGNER_STATUS},
};

/// Implements the Signer API and provides a service for signing requests
pub struct SigningService;
Expand Down Expand Up @@ -72,13 +77,15 @@ impl SigningService {
info!(version = COMMIT_BOOST_VERSION, modules =? module_ids, port =? config.server_port, loaded_consensus, loaded_proxies, "Starting signing service");

let state = SigningState { manager: RwLock::new(manager).into(), jwts: config.jwts.into() };
SigningService::init_metrics()?;

let app = axum::Router::new()
.route(REQUEST_SIGNATURE_PATH, post(handle_request_signature))
.route(GET_PUBKEYS_PATH, get(handle_get_pubkeys))
.route(GENERATE_PROXY_KEY_PATH, post(handle_generate_proxy))
.with_state(state.clone())
.route_layer(middleware::from_fn_with_state(state.clone(), jwt_auth));
.route_layer(middleware::from_fn_with_state(state.clone(), jwt_auth))
.route_layer(middleware::from_fn(log_request));
let status_router = axum::Router::new().route(STATUS_PATH, get(handle_status));

let address = SocketAddr::from(([0, 0, 0, 0], config.server_port));
Expand All @@ -88,6 +95,10 @@ impl SigningService {
.await
.wrap_err("signer server exited")
}

fn init_metrics() -> Result<()> {
MetricsProvider::load_and_run(SIGNER_METRICS_REGISTRY.clone())
}
}

/// Authentication middleware layer
Expand All @@ -109,6 +120,14 @@ async fn jwt_auth(
Ok(next.run(req).await)
}

/// Requests logging middleware layer
async fn log_request(req: Request, next: Next) -> Result<Response, SignerModuleError> {
let url = &req.uri().clone();
let response = next.run(req).await;
SIGNER_STATUS.with_label_values(&[response.status().as_str(), uri_to_tag(url)]).inc();
Ok(response)
}

/// Status endpoint for the Signer API
async fn handle_status() -> Result<impl IntoResponse, SignerModuleError> {
Ok((StatusCode::OK, "OK"))
Expand Down
Loading
Loading