Skip to content

Commit

Permalink
Add detailed metrics reporting for packet filtering (solana-labs#1421)
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry authored May 18, 2024
1 parent ef8d362 commit 4178c69
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 94 deletions.
1 change: 1 addition & 0 deletions core/src/banking_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ mod latest_unprocessed_votes;
mod leader_slot_timing_metrics;
mod multi_iterator_scanner;
mod packet_deserializer;
mod packet_filter;
mod packet_receiver;
mod read_write_account_set;
#[allow(dead_code)]
Expand Down
29 changes: 9 additions & 20 deletions core/src/banking_stage/immutable_deserialized_packet.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use {
solana_cost_model::block_cost_limits::BUILT_IN_INSTRUCTION_COSTS,
super::packet_filter::PacketFilterFailure,
solana_perf::packet::Packet,
solana_runtime::compute_budget_details::{ComputeBudgetDetails, GetComputeBudgetDetails},
solana_sdk::{
Expand All @@ -8,7 +8,6 @@ use {
message::Message,
pubkey::Pubkey,
sanitize::SanitizeError,
saturating_add_assign,
short_vec::decode_shortu16_len,
signature::Signature,
transaction::{
Expand All @@ -35,6 +34,8 @@ pub enum DeserializedPacketError {
PrioritizationFailure,
#[error("vote transaction failure")]
VoteTransactionError,
#[error("Packet filter failure: {0}")]
FailedFilter(#[from] PacketFilterFailure),
}

#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -101,22 +102,6 @@ impl ImmutableDeserializedPacket {
self.compute_budget_details.clone()
}

/// Returns true if the transaction's compute unit limit is at least as
/// large as the sum of the static builtins' costs.
/// This is a simple sanity check so the leader can discard transactions
/// which are statically known to exceed the compute budget, and will
/// result in no useful state-change.
pub fn compute_unit_limit_above_static_builtins(&self) -> bool {
let mut static_builtin_cost_sum: u64 = 0;
for (program_id, _) in self.transaction.get_message().program_instructions_iter() {
if let Some(ix_cost) = BUILT_IN_INSTRUCTION_COSTS.get(program_id) {
saturating_add_assign!(static_builtin_cost_sum, *ix_cost);
}
}

self.compute_unit_limit() >= static_builtin_cost_sum
}

// This function deserializes packets into transactions, computes the blake3 hash of transaction
// messages, and verifies secp256k1 instructions.
pub fn build_sanitized_transaction(
Expand Down Expand Up @@ -197,7 +182,11 @@ mod tests {
// 1. compute_unit_limit under static builtins
// 2. compute_unit_limit equal to static builtins
// 3. compute_unit_limit above static builtins
for (cu_limit, expectation) in [(250, false), (300, true), (350, true)] {
for (cu_limit, expectation) in [
(250, Err(PacketFilterFailure::InsufficientComputeLimit)),
(300, Ok(())),
(350, Ok(())),
] {
let keypair = Keypair::new();
let bpf_program_id = Pubkey::new_unique();
let ixs = vec![
Expand All @@ -214,7 +203,7 @@ mod tests {
let packet = Packet::from_data(None, tx).unwrap();
let deserialized_packet = ImmutableDeserializedPacket::new(packet).unwrap();
assert_eq!(
deserialized_packet.compute_unit_limit_above_static_builtins(),
deserialized_packet.check_insufficent_compute_unit_limit(),
expectation
);
}
Expand Down
127 changes: 89 additions & 38 deletions core/src/banking_stage/leader_slot_metrics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use {
super::{
leader_slot_timing_metrics::{LeaderExecuteAndCommitTimings, LeaderSlotTimingMetrics},
packet_deserializer::PacketReceiverStats,
unprocessed_transaction_storage::{
InsertPacketBatchSummary, UnprocessedTransactionStorage,
},
Expand Down Expand Up @@ -113,6 +114,21 @@ struct LeaderSlotPacketCountMetrics {
// total number of packets TPU received from sigverify that failed signature verification.
newly_failed_sigverify_count: u64,

// total number of packets filtered due to sanitization failures during receiving from sigverify
failed_sanitization_count: u64,

// total number of packets filtered due to prioritization failures during receiving from sigverify
failed_prioritization_count: u64,

// total number of packets filtered due to insufficient compute limits during receiving from sigverify
insufficient_compute_limit_count: u64,

// total number of packets filtered due to excessive precompile signatures during receiving from sigverify
excessive_precompile_count: u64,

// total number of invalid vote packets filtered out during receiving from sigverify
invalid_votes_count: u64,

// total number of dropped packet due to the thread's buffered packets capacity being reached.
exceeded_buffer_limit_dropped_packets_count: u64,

Expand Down Expand Up @@ -203,120 +219,145 @@ impl LeaderSlotPacketCountMetrics {
datapoint_info!(
"banking_stage-leader_slot_packet_counts",
"id" => id,
("slot", slot as i64, i64),
("slot", slot, i64),
(
"total_new_valid_packets",
self.total_new_valid_packets as i64,
self.total_new_valid_packets,
i64
),
(
"newly_failed_sigverify_count",
self.newly_failed_sigverify_count as i64,
self.newly_failed_sigverify_count,
i64
),
(
"failed_sanitization_count",
self.failed_sanitization_count,
i64
),
(
"failed_prioritization_count",
self.failed_prioritization_count,
i64
),
(
"insufficient_compute_limit_count",
self.insufficient_compute_limit_count,
i64
),
(
"excessive_precompile_count",
self.excessive_precompile_count,
i64
),
(
"invalid_votes_count",
self.invalid_votes_count,
i64
),
(
"exceeded_buffer_limit_dropped_packets_count",
self.exceeded_buffer_limit_dropped_packets_count as i64,
self.exceeded_buffer_limit_dropped_packets_count,
i64
),
(
"newly_buffered_packets_count",
self.newly_buffered_packets_count as i64,
self.newly_buffered_packets_count,
i64
),
(
"retryable_packets_filtered_count",
self.retryable_packets_filtered_count as i64,
self.retryable_packets_filtered_count,
i64
),
(
"transactions_attempted_execution_count",
self.transactions_attempted_execution_count as i64,
self.transactions_attempted_execution_count,
i64
),
(
"committed_transactions_count",
self.committed_transactions_count as i64,
self.committed_transactions_count,
i64
),
(
"committed_transactions_with_successful_result_count",
self.committed_transactions_with_successful_result_count as i64,
self.committed_transactions_with_successful_result_count,
i64
),
(
"retryable_errored_transaction_count",
self.retryable_errored_transaction_count as i64,
self.retryable_errored_transaction_count,
i64
),
(
"retryable_packets_count",
self.retryable_packets_count as i64,
self.retryable_packets_count,
i64
),
(
"nonretryable_errored_transactions_count",
self.nonretryable_errored_transactions_count as i64,
self.nonretryable_errored_transactions_count,
i64
),
(
"executed_transactions_failed_commit_count",
self.executed_transactions_failed_commit_count as i64,
self.executed_transactions_failed_commit_count,
i64
),
(
"account_lock_throttled_transactions_count",
self.account_lock_throttled_transactions_count as i64,
self.account_lock_throttled_transactions_count,
i64
),
(
"account_locks_limit_throttled_transactions_count",
self.account_locks_limit_throttled_transactions_count as i64,
self.account_locks_limit_throttled_transactions_count,
i64
),
(
"cost_model_throttled_transactions_count",
self.cost_model_throttled_transactions_count as i64,
self.cost_model_throttled_transactions_count,
i64
),
(
"failed_forwarded_packets_count",
self.failed_forwarded_packets_count as i64,
self.failed_forwarded_packets_count,
i64
),
(
"successful_forwarded_packets_count",
self.successful_forwarded_packets_count as i64,
self.successful_forwarded_packets_count,
i64
),
(
"packet_batch_forward_failure_count",
self.packet_batch_forward_failure_count as i64,
self.packet_batch_forward_failure_count,
i64
),
(
"cleared_from_buffer_after_forward_count",
self.cleared_from_buffer_after_forward_count as i64,
self.cleared_from_buffer_after_forward_count,
i64
),
(
"forwardable_batches_count",
self.forwardable_batches_count as i64,
self.forwardable_batches_count,
i64
),
(
"end_of_slot_unprocessed_buffer_len",
self.end_of_slot_unprocessed_buffer_len as i64,
self.end_of_slot_unprocessed_buffer_len,
i64
),
(
"min_prioritization_fees",
self.min_prioritization_fees as i64,
self.min_prioritization_fees,
i64
),
(
"max_prioritization_fees",
self.max_prioritization_fees as i64,
self.max_prioritization_fees,
i64
),
);
Expand Down Expand Up @@ -656,24 +697,34 @@ impl LeaderSlotMetricsTracker {
}

// Packet inflow/outflow/processing metrics
pub(crate) fn increment_total_new_valid_packets(&mut self, count: u64) {
pub(crate) fn increment_received_packet_counts(&mut self, stats: PacketReceiverStats) {
if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
let metrics = &mut leader_slot_metrics.packet_count_metrics;
let PacketReceiverStats {
passed_sigverify_count,
failed_sigverify_count,
invalid_vote_count,
failed_prioritization_count,
failed_sanitization_count,
excessive_precompile_count,
insufficient_compute_limit_count,
} = stats;

saturating_add_assign!(metrics.total_new_valid_packets, passed_sigverify_count);
saturating_add_assign!(metrics.newly_failed_sigverify_count, failed_sigverify_count);
saturating_add_assign!(metrics.invalid_votes_count, invalid_vote_count);
saturating_add_assign!(
leader_slot_metrics
.packet_count_metrics
.total_new_valid_packets,
count
metrics.failed_prioritization_count,
failed_prioritization_count
);
}
}

pub(crate) fn increment_newly_failed_sigverify_count(&mut self, count: u64) {
if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
saturating_add_assign!(metrics.failed_sanitization_count, failed_sanitization_count);
saturating_add_assign!(
leader_slot_metrics
.packet_count_metrics
.newly_failed_sigverify_count,
count
metrics.excessive_precompile_count,
excessive_precompile_count
);
saturating_add_assign!(
metrics.insufficient_compute_limit_count,
insufficient_compute_limit_count
);
}
}
Expand Down
Loading

0 comments on commit 4178c69

Please sign in to comment.