Skip to content
Open
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
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ mod macros;
/// Configuration for the Builder binary.
pub mod config;

/// Centralized metrics definitions.
pub mod metrics;

/// Quincey client for signing requests.
pub mod quincey;

Expand Down
220 changes: 220 additions & 0 deletions src/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
//! Builder metrics definitions
//!
//! This module centralizes all metric definitions for the builder.
//!
//! ## Counters
//! - Quincey signature requests (success/failure)
//! - Flashbots submissions (success/failure)
//! - Block builds
//! - Transaction outcomes
//!
//! ## Histograms
//! - Quincey signature duration
//! - Nonce fetch duration
//! - Transaction mine time
//! - Block transaction count

use init4_bin_base::deps::metrics::{
Counter, Histogram, counter, describe_counter, describe_histogram, histogram,
};
use std::sync::LazyLock;

// -- Quincey --
const QUINCEY_SIGNATURES: &str = "signet.builder.quincey_signatures";
const QUINCEY_SIGNATURES_HELP: &str = "Number of successful Quincey signature requests";

const QUINCEY_SIGNATURE_FAILURES: &str = "signet.builder.quincey_signature_failures";
const QUINCEY_SIGNATURE_FAILURES_HELP: &str = "Number of failed Quincey signature requests";

const QUINCEY_SIGNATURE_DURATION_MS: &str = "signet.builder.quincey_signature_duration_ms";
const QUINCEY_SIGNATURE_DURATION_MS_HELP: &str =
"Duration of Quincey signature requests in milliseconds";

// -- Nonce --
const NONCE_FETCH_DURATION_MS: &str = "signet.builder.nonce_fetch_duration_ms";
const NONCE_FETCH_DURATION_MS_HELP: &str = "Duration of nonce fetch requests in milliseconds";

// -- Flashbots --
const FLASHBOTS_BUNDLES_SUBMITTED: &str = "signet.builder.flashbots.bundles_submitted";
const FLASHBOTS_BUNDLES_SUBMITTED_HELP: &str =
"Number of bundles successfully submitted to Flashbots";

const FLASHBOTS_SUBMISSION_FAILURES: &str = "signet.builder.flashbots.submission_failures";
const FLASHBOTS_SUBMISSION_FAILURES_HELP: &str = "Number of failed Flashbots bundle submissions";

const FLASHBOTS_BUNDLE_PREP_FAILURES: &str = "signet.builder.flashbots.bundle_prep_failures";
const FLASHBOTS_BUNDLE_PREP_FAILURES_HELP: &str = "Number of failed bundle preparations";

const FLASHBOTS_EMPTY_BLOCKS: &str = "signet.builder.flashbots.empty_block";
const FLASHBOTS_EMPTY_BLOCKS_HELP: &str = "Number of empty blocks skipped";

const FLASHBOTS_SUBMISSIONS: &str = "signet.builder.flashbots.submissions";
const FLASHBOTS_SUBMISSIONS_HELP: &str = "Number of submission attempts to Flashbots";

const FLASHBOTS_SUBMISSION_DURATION_MS: &str = "signet.builder.flashbots.submission_duration_ms";
const FLASHBOTS_SUBMISSION_DURATION_MS_HELP: &str =
"Duration of Flashbots bundle submission requests in milliseconds";

// -- Block Building --
const BUILT_BLOCKS: &str = "signet.builder.built_blocks";
const BUILT_BLOCKS_HELP: &str = "Number of blocks built by the simulator";

const BUILT_BLOCKS_TX_COUNT: &str = "signet.builder.built_blocks.tx_count";
const BUILT_BLOCKS_TX_COUNT_HELP: &str = "Number of transactions in built blocks";

// -- Transaction Outcomes --
const TX_MINE_TIME_MS: &str = "signet.builder.tx_mine_time_ms";
const TX_MINE_TIME_MS_HELP: &str = "Time for transaction to be mined in milliseconds";

const TX_SUCCEEDED: &str = "signet.builder.tx_succeeded";
const TX_SUCCEEDED_HELP: &str = "Number of transactions that succeeded";

const TX_REVERTED: &str = "signet.builder.tx_reverted";
const TX_REVERTED_HELP: &str = "Number of transactions that reverted";

const TX_NOT_MINED: &str = "signet.builder.tx_not_mined";
const TX_NOT_MINED_HELP: &str = "Number of transactions that timed out without being mined";

const RPC_ERROR: &str = "signet.builder.rpc_error";
const RPC_ERROR_HELP: &str = "Number of RPC errors encountered";

static DESCRIBE: LazyLock<()> = LazyLock::new(|| {
// Quincey
describe_counter!(QUINCEY_SIGNATURES, QUINCEY_SIGNATURES_HELP);
describe_counter!(QUINCEY_SIGNATURE_FAILURES, QUINCEY_SIGNATURE_FAILURES_HELP);
describe_histogram!(QUINCEY_SIGNATURE_DURATION_MS, QUINCEY_SIGNATURE_DURATION_MS_HELP);

// Nonce
describe_histogram!(NONCE_FETCH_DURATION_MS, NONCE_FETCH_DURATION_MS_HELP);

// Flashbots
describe_counter!(FLASHBOTS_BUNDLES_SUBMITTED, FLASHBOTS_BUNDLES_SUBMITTED_HELP);
describe_counter!(FLASHBOTS_SUBMISSION_FAILURES, FLASHBOTS_SUBMISSION_FAILURES_HELP);
describe_counter!(FLASHBOTS_BUNDLE_PREP_FAILURES, FLASHBOTS_BUNDLE_PREP_FAILURES_HELP);
describe_counter!(FLASHBOTS_EMPTY_BLOCKS, FLASHBOTS_EMPTY_BLOCKS_HELP);
describe_counter!(FLASHBOTS_SUBMISSIONS, FLASHBOTS_SUBMISSIONS_HELP);
describe_histogram!(FLASHBOTS_SUBMISSION_DURATION_MS, FLASHBOTS_SUBMISSION_DURATION_MS_HELP);

// Block building
describe_counter!(BUILT_BLOCKS, BUILT_BLOCKS_HELP);
describe_histogram!(BUILT_BLOCKS_TX_COUNT, BUILT_BLOCKS_TX_COUNT_HELP);

// Transaction outcomes
describe_histogram!(TX_MINE_TIME_MS, TX_MINE_TIME_MS_HELP);
describe_counter!(TX_SUCCEEDED, TX_SUCCEEDED_HELP);
describe_counter!(TX_REVERTED, TX_REVERTED_HELP);
describe_counter!(TX_NOT_MINED, TX_NOT_MINED_HELP);
describe_counter!(RPC_ERROR, RPC_ERROR_HELP);
});

// -- Quincey --

/// Counter for successful Quincey signature requests.
pub fn quincey_signatures() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(QUINCEY_SIGNATURES)
}

/// Counter for failed Quincey signature requests.
pub fn quincey_signature_failures() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(QUINCEY_SIGNATURE_FAILURES)
}

/// Histogram for Quincey signature request duration in milliseconds.
pub fn quincey_signature_duration_ms() -> Histogram {
LazyLock::force(&DESCRIBE);
histogram!(QUINCEY_SIGNATURE_DURATION_MS)
}

// -- Nonce --

/// Histogram for nonce fetch duration in milliseconds.
pub fn nonce_fetch_duration_ms() -> Histogram {
LazyLock::force(&DESCRIBE);
histogram!(NONCE_FETCH_DURATION_MS)
}

// -- Flashbots --

/// Counter for bundles successfully submitted to Flashbots.
pub fn flashbots_bundles_submitted() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(FLASHBOTS_BUNDLES_SUBMITTED)
}

/// Counter for failed Flashbots bundle submissions.
pub fn flashbots_submission_failures() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(FLASHBOTS_SUBMISSION_FAILURES)
}

/// Counter for failed bundle preparations.
pub fn flashbots_bundle_prep_failures() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(FLASHBOTS_BUNDLE_PREP_FAILURES)
}

/// Counter for empty blocks that were skipped.
pub fn flashbots_empty_blocks() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(FLASHBOTS_EMPTY_BLOCKS)
}

/// Counter for submission attempts to Flashbots.
pub fn flashbots_submissions() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(FLASHBOTS_SUBMISSIONS)
}

/// Histogram for Flashbots bundle submission duration in milliseconds.
pub fn flashbots_submission_duration_ms() -> Histogram {
LazyLock::force(&DESCRIBE);
histogram!(FLASHBOTS_SUBMISSION_DURATION_MS)
}

// -- Block Building --

/// Counter for blocks built by the simulator.
pub fn built_blocks() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(BUILT_BLOCKS)
}

/// Histogram for transaction count in built blocks.
pub fn built_blocks_tx_count() -> Histogram {
LazyLock::force(&DESCRIBE);
histogram!(BUILT_BLOCKS_TX_COUNT)
}

// -- Transaction Outcomes --

/// Histogram for transaction mine time in milliseconds.
pub fn tx_mine_time_ms() -> Histogram {
LazyLock::force(&DESCRIBE);
histogram!(TX_MINE_TIME_MS)
}

/// Counter for transactions that succeeded.
pub fn tx_succeeded() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(TX_SUCCEEDED)
}

/// Counter for transactions that reverted.
pub fn tx_reverted() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(TX_REVERTED)
}

/// Counter for transactions that timed out without being mined.
pub fn tx_not_mined() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(TX_NOT_MINED)
}

/// Counter for RPC errors encountered.
pub fn rpc_error() -> Counter {
LazyLock::force(&DESCRIBE);
counter!(RPC_ERROR)
}
10 changes: 4 additions & 6 deletions src/tasks/block/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
//! and turns them into valid Pecorino blocks for network submission.
use crate::{
config::{BuilderConfig, HostProvider, RuProvider},
metrics,
tasks::env::SimEnv,
};
use alloy::consensus::Header;
use init4_bin_base::{
deps::metrics::{counter, histogram},
utils::calc::SlotCalculator,
};
use init4_bin_base::utils::calc::SlotCalculator;
use signet_sim::{BlockBuild, BuiltBlock, SimCache};
use signet_types::constants::SignetSystemConstants;
use std::time::{Duration, Instant};
Expand Down Expand Up @@ -158,8 +156,8 @@ impl Simulator {
block_number = built_block.block_number(),
"block simulation completed",
);
counter!("signet.builder.built_blocks").increment(1);
histogram!("signet.builder.built_blocks.tx_count").record(built_block.tx_count() as u32);
metrics::built_blocks().increment(1);
metrics::built_blocks_tx_count().record(built_block.tx_count() as u32);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these lines should both be collapsed into metrcis::record_bulit_block(&block) and the logic to increment, etc should be in the metrics file


Ok(built_block)
}
Expand Down
13 changes: 6 additions & 7 deletions src/tasks/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::config::HostProvider;
use crate::{config::HostProvider, metrics};
use alloy::{
primitives::TxHash,
providers::{PendingTransactionBuilder, PendingTransactionError, Provider as _, WatchTxError},
};
use init4_bin_base::deps::metrics::{counter, histogram};
use std::time::{Duration, Instant};
use tokio::{sync::mpsc, task::JoinHandle};
use tracing::{Instrument, debug, error, info_span};
Expand Down Expand Up @@ -47,24 +46,24 @@ impl MetricsTask {
Ok(receipt) => {
// record how long it took to mine the transaction
// potential improvement: use the block timestamp to calculate the time elapsed
histogram!("metrics.tx_mine_time").record(start.elapsed().as_millis() as f64);
metrics::tx_mine_time_ms().record(start.elapsed().as_millis() as f64);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto


// log whether the transaction reverted
if receipt.status() {
counter!("metrics.tx_succeeded").increment(1);
metrics::tx_succeeded().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

debug!("tx succeeded");
} else {
counter!("metrics.tx_reverted").increment(1);
metrics::tx_reverted().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

debug!("tx reverted");
}
}
Err(PendingTransactionError::TxWatcher(WatchTxError::Timeout)) => {
// log that the transaction timed out
counter!("metrics.tx_not_mined").increment(1);
metrics::tx_not_mined().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

debug!("tx not mined");
}
Err(e) => {
counter!("metrics.rpc_error").increment(1);
metrics::rpc_error().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

error!(error = ?e, "rpc error");
}
}
Expand Down
18 changes: 12 additions & 6 deletions src/tasks/submit/flashbots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! submits them to the Flashbots relay as bundles.
use crate::{
config::{BuilderConfig, FlashbotsProvider, HostProvider, ZenithInstance},
metrics,
quincey::Quincey,
tasks::{block::sim::SimResult, submit::SubmitPrep},
};
Expand All @@ -12,7 +13,8 @@ use alloy::{
rpc::types::mev::{BundleItem, MevSendBundle, ProtocolVersion},
};
use eyre::OptionExt;
use init4_bin_base::{deps::metrics::counter, utils::signer::LocalOrAws};
use init4_bin_base::utils::signer::LocalOrAws;
use std::time::Instant;
use tokio::{sync::mpsc, task::JoinHandle};
use tracing::{Instrument, debug, debug_span};

Expand Down Expand Up @@ -120,7 +122,7 @@ impl FlashbotsTask {
/// Sends the transaction hash to the outbound channel for monitoring.
/// Logs a debug message if the channel is closed.
fn track_outbound_tx(&self, envelope: &alloy::consensus::TxEnvelope) {
counter!("signet.builder.flashbots.").increment(1);
metrics::flashbots_submissions().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto here. we don't want the caller to be responsible for the .increment(1), as it requires knowing the metric semantics

let hash = *envelope.tx_hash();
if self.outbound.send(hash).is_err() {
debug!("outbound channel closed, could not track tx hash");
Expand Down Expand Up @@ -166,7 +168,7 @@ impl FlashbotsTask {

// Don't submit empty blocks
if sim_result.block.is_empty() {
counter!("signet.builder.flashbots.empty_block").increment(1);
metrics::flashbots_empty_blocks().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

span_debug!(span, "received empty block - skipping");
continue;
}
Expand All @@ -175,7 +177,7 @@ impl FlashbotsTask {
// Prepare a MEV bundle with the configured call type from the sim result
let result =
self.prepare(&sim_result).instrument(span.clone()).await.inspect_err(|error| {
counter!("signet.builder.flashbots.bundle_prep_failures").increment(1);
metrics::flashbots_bundle_prep_failures().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

span_debug!(span, %error, "bundle preparation failed");
});
let bundle = match result {
Expand All @@ -195,24 +197,28 @@ impl FlashbotsTask {
let signer = self.signer.clone();

tokio::spawn(async move {
let start = Instant::now();
let response = flashbots
.send_mev_bundle(bundle.clone())
.with_auth(signer.clone())
.into_future()
.instrument(submit_span.clone())
.await;

metrics::flashbots_submission_duration_ms()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

.record(start.elapsed().as_millis() as f64);

match response {
Ok(resp) => {
counter!("signet.builder.flashbots.bundles_submitted").increment(1);
metrics::flashbots_bundles_submitted().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

span_debug!(
submit_span,
hash = resp.map(|r| r.bundle_hash.to_string()),
"received bundle hash after submitted to flashbots"
);
}
Err(err) => {
counter!("signet.builder.flashbots.submission_failures").increment(1);
metrics::flashbots_submission_failures().increment(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

span_error!(submit_span, %err, "MEV bundle submission failed - error returned");
}
}
Expand Down
Loading
Loading