Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement signer metrics exporter #1084

Merged
merged 13 commits into from
Dec 10, 2024
116 changes: 103 additions & 13 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ config = "0.11.0"
futures = "0.3.24"
hashbrown = "0.14.5"
http = "1.1.0"
metrics = "0.24"
metrics-exporter-prometheus = { version = "0.16", default-features = false, features = ["http-listener"] }
# This is necessary to compile the AWS Lambda as a lambda.
openssl = { version = "0.10.66", features = ["vendored"] }
p256k1 = "7.1.0"
Expand Down
2 changes: 2 additions & 0 deletions signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ config = "0.14"
futures.workspace = true
hashbrown.workspace = true
libp2p.workspace = true
metrics.workspace = true
metrics-exporter-prometheus.workspace = true
p256k1.workspace = true
prost.workspace = true
rand.workspace = true
Expand Down
26 changes: 26 additions & 0 deletions signer/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
fn main() {
set_up_build_info();
// compile_protos();
}

pub fn set_up_build_info() {
let output = std::process::Command::new("rustc")
.arg("--version")
.output()
.expect("Failed to execute rustc");

let version = String::from_utf8_lossy(&output.stdout);

let git_hash = std::process::Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).to_string())
.unwrap_or_default();

let env_abi = std::env::var("CARGO_CFG_TARGET_ENV").unwrap();
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();

// We capture these variables in our binary and use them in the
// build_info metric.
println!("cargo:rustc-env=CARGO_CFG_TARGET_ENV={}", env_abi.trim());
println!("cargo:rustc-env=CARGO_CFG_TARGET_ARCH={}", arch.trim());
println!("cargo:rustc-env=GIT_COMMIT={}", git_hash.trim());
println!("cargo:rustc-env=RUSTC_VERSION={}", version.trim());
}

pub fn compile_protos() {
let workingdir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
Expand Down
8 changes: 8 additions & 0 deletions signer/src/api/new_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use std::sync::OnceLock;
use crate::context::Context;
use crate::emily_client::EmilyInteract;
use crate::error::Error;
use crate::metrics::Metrics;
use crate::metrics::STACKS_BLOCKCHAIN;
use crate::stacks::events::CompletedDepositEvent;
use crate::stacks::events::KeyRotationEvent;
use crate::stacks::events::RegistryEvent;
Expand Down Expand Up @@ -79,6 +81,12 @@ enum UpdateResult {
#[tracing::instrument(skip_all, name = "new-block")]
pub async fn new_block_handler(state: State<ApiState<impl Context>>, body: String) -> StatusCode {
tracing::debug!("received a new block event from stacks-core");
metrics::counter!(
Metrics::BlocksObservedTotal,
"blockchain" => STACKS_BLOCKCHAIN,
)
.increment(1);

let api = state.0;

let registry_address = SBTC_REGISTRY_IDENTIFIER.get_or_init(|| {
Expand Down
36 changes: 32 additions & 4 deletions signer/src/block_observer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use crate::context::SbtcLimits;
use crate::context::SignerEvent;
use crate::emily_client::EmilyInteract;
use crate::error::Error;
use crate::metrics::Metrics;
use crate::metrics::BITCOIN_BLOCKCHAIN;
use crate::stacks::api::StacksInteract;
use crate::stacks::api::TenureBlocks;
use crate::storage;
Expand Down Expand Up @@ -137,6 +139,11 @@ where
match poll.await {
Ok(Some(Ok(block_hash))) => {
tracing::info!("observed new bitcoin block from stream");
metrics::counter!(
Metrics::BlocksObservedTotal,
"blockchain" => BITCOIN_BLOCKCHAIN,
)
.increment(1);

let next_blocks = match self.next_blocks_to_process(block_hash).await {
Ok(blocks) => blocks,
Expand Down Expand Up @@ -203,17 +210,31 @@ impl<C: Context, B> BlockObserver<C, B> {
#[tracing::instrument(skip_all)]
pub async fn load_requests(&self, requests: &[CreateDepositRequest]) -> Result<(), Error> {
let mut deposit_requests = Vec::new();
let bitcoin_client = self.context.get_bitcoin_client();

for request in requests {
let deposit = request
.validate(&self.context.get_bitcoin_client())
.validate(&bitcoin_client)
.await
.inspect_err(|error| tracing::warn!(%error, "could not validate deposit request"));

// We log the error above, so we just need to extract the
// deposit now.
if let Ok(Some(deposit)) = deposit {
deposit_requests.push(deposit);
}
let deposit_status = match deposit {
Ok(Some(deposit)) => {
deposit_requests.push(deposit);
"success"
}
Ok(None) => "unconfirmed",
Err(_) => "failed",
};

metrics::counter!(
Metrics::DepositRequestsTotal,
"blockchain" => BITCOIN_BLOCKCHAIN,
"status" => deposit_status,
)
.increment(1);
}

self.store_deposit_requests(deposit_requests).await?;
Expand Down Expand Up @@ -435,6 +456,13 @@ impl<C: Context, B> BlockObserver<C, B> {

for prevout in tx_info.to_inputs(&signer_script_pubkeys) {
db.write_tx_prevout(&prevout).await?;
if prevout.prevout_type == model::TxPrevoutType::Deposit {
metrics::counter!(
Metrics::DepositsSweptTotal,
"blockchain" => BITCOIN_BLOCKCHAIN,
)
.increment(1);
}
}

for output in tx_info.to_outputs(&signer_script_pubkeys) {
Expand Down
9 changes: 8 additions & 1 deletion signer/src/config/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ dkg_max_duration = 120
# Environment: SIGNER_SIGNER__DKG_BEGIN_PAUSE
# dkg_begin_pause = 10

# When defined, this field sets the scrape endpoint as an IPv4 or IPv6
# socket address for exporting metrics for Prometheus.
#
# Required: false
# Environment: SIGNER_SIGNER__PROMETHEUS_EXPORTER_ENDPOINT
# prometheus_exporter_endpoint = "[::]:9184"

# !! ==============================================================================
# !! Stacks Event Observer Configuration
# !!
Expand Down Expand Up @@ -277,4 +284,4 @@ public_endpoints = []
# Default: false
# Required: false
# Environment: SIGNER_SIGNER__P2P__ENABLE_MDNS
enable_mdns = true
enable_mdns = true
Loading
Loading