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

add precompile signature metrics to cost tracker #133

Merged
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
8 changes: 6 additions & 2 deletions cost-model/src/block_cost_limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ pub const MAX_CONCURRENCY: u64 = 4;
pub const COMPUTE_UNIT_TO_US_RATIO: u64 = 30;
/// Number of compute units for one signature verification.
pub const SIGNATURE_COST: u64 = COMPUTE_UNIT_TO_US_RATIO * 24;
/// Number of compute units for one secp256k1 signature verification.
pub const SECP256K1_VERIFY_COST: u64 = COMPUTE_UNIT_TO_US_RATIO * 223;
/// Number of compute units for one ed25519 signature verification.
pub const ED25519_VERIFY_COST: u64 = COMPUTE_UNIT_TO_US_RATIO * 76;
/// Number of compute units for one write lock
pub const WRITE_LOCK_UNITS: u64 = COMPUTE_UNIT_TO_US_RATIO * 10;
/// Number of data bytes per compute units
Expand All @@ -43,8 +47,8 @@ lazy_static! {
(bpf_loader::id(), solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS),
(loader_v4::id(), solana_loader_v4_program::DEFAULT_COMPUTE_UNITS),
// Note: These are precompile, run directly in bank during sanitizing;
(secp256k1_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24),
(ed25519_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24),
(secp256k1_program::id(), 0),
(ed25519_program::id(), 0),
]
.iter()
.cloned()
Expand Down
24 changes: 21 additions & 3 deletions cost-model/src/cost_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl CostModel {
} else {
let mut tx_cost = UsageCostDetails::new_with_default_capacity();

tx_cost.signature_cost = Self::get_signature_cost(transaction);
Self::get_signature_cost(&mut tx_cost, transaction);
Self::get_write_lock_cost(&mut tx_cost, transaction, feature_set);
Self::get_transaction_cost(&mut tx_cost, transaction, feature_set);
tx_cost.account_data_size = Self::calculate_account_data_size(transaction);
Expand All @@ -53,8 +53,26 @@ impl CostModel {
}
}

fn get_signature_cost(transaction: &SanitizedTransaction) -> u64 {
transaction.signatures().len() as u64 * SIGNATURE_COST
fn get_signature_cost(tx_cost: &mut UsageCostDetails, transaction: &SanitizedTransaction) {
let signatures_count_detail = transaction.message().get_signature_details();
tx_cost.num_transaction_signatures = signatures_count_detail.num_transaction_signatures();
tx_cost.num_secp256k1_instruction_signatures =
signatures_count_detail.num_secp256k1_instruction_signatures();
tx_cost.num_ed25519_instruction_signatures =
signatures_count_detail.num_ed25519_instruction_signatures();
tx_cost.signature_cost = signatures_count_detail
.num_transaction_signatures()
.saturating_mul(SIGNATURE_COST)
.saturating_add(
signatures_count_detail
.num_secp256k1_instruction_signatures()
.saturating_mul(SECP256K1_VERIFY_COST),
)
.saturating_add(
signatures_count_detail
.num_ed25519_instruction_signatures()
.saturating_mul(ED25519_VERIFY_COST),
);
}

fn get_writable_accounts(transaction: &SanitizedTransaction) -> Vec<Pubkey> {
Expand Down
42 changes: 42 additions & 0 deletions cost-model/src/cost_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub struct CostTracker {
vote_cost: u64,
transaction_count: u64,
account_data_size: u64,
transaction_signature_count: u64,
secp256k1_instruction_signature_count: u64,
ed25519_instruction_signature_count: u64,
}

impl Default for CostTracker {
Expand All @@ -77,6 +80,9 @@ impl Default for CostTracker {
vote_cost: 0,
transaction_count: 0,
account_data_size: 0,
transaction_signature_count: 0,
secp256k1_instruction_signature_count: 0,
ed25519_instruction_signature_count: 0,
}
}
}
Expand Down Expand Up @@ -153,6 +159,21 @@ impl CostTracker {
("costliest_account", costliest_account.to_string(), String),
("costliest_account_cost", costliest_account_cost as i64, i64),
("account_data_size", self.account_data_size, i64),
(
"transaction_signature_count",
self.transaction_signature_count,
i64
),
(
"secp256k1_instruction_signature_count",
self.secp256k1_instruction_signature_count,
i64
),
(
"ed25519_instruction_signature_count",
self.ed25519_instruction_signature_count,
i64
),
);
}

Expand Down Expand Up @@ -213,6 +234,18 @@ impl CostTracker {
self.add_transaction_execution_cost(tx_cost, tx_cost.sum());
saturating_add_assign!(self.account_data_size, tx_cost.account_data_size());
saturating_add_assign!(self.transaction_count, 1);
saturating_add_assign!(
self.transaction_signature_count,
tx_cost.num_transaction_signatures()
);
saturating_add_assign!(
self.secp256k1_instruction_signature_count,
tx_cost.num_secp256k1_instruction_signatures()
);
saturating_add_assign!(
self.ed25519_instruction_signature_count,
tx_cost.num_ed25519_instruction_signatures()
);
}

fn remove_transaction_cost(&mut self, tx_cost: &TransactionCost) {
Expand All @@ -222,6 +255,15 @@ impl CostTracker {
.account_data_size
.saturating_sub(tx_cost.account_data_size());
self.transaction_count = self.transaction_count.saturating_sub(1);
self.transaction_signature_count = self
.transaction_signature_count
.saturating_sub(tx_cost.num_transaction_signatures());
self.secp256k1_instruction_signature_count = self
.secp256k1_instruction_signature_count
.saturating_sub(tx_cost.num_secp256k1_instruction_signatures());
self.ed25519_instruction_signature_count = self
.ed25519_instruction_signature_count
.saturating_sub(tx_cost.num_ed25519_instruction_signatures());
}

/// Apply additional actual execution units to cost_tracker
Expand Down
31 changes: 31 additions & 0 deletions cost-model/src/transaction_cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,27 @@ impl TransactionCost {
Self::Transaction(usage_cost) => &usage_cost.writable_accounts,
}
}

pub fn num_transaction_signatures(&self) -> u64 {
match self {
Self::SimpleVote { .. } => 1,
Self::Transaction(usage_cost) => usage_cost.num_transaction_signatures,
}
}

pub fn num_secp256k1_instruction_signatures(&self) -> u64 {
match self {
Self::SimpleVote { .. } => 0,
Self::Transaction(usage_cost) => usage_cost.num_secp256k1_instruction_signatures,
}
}

pub fn num_ed25519_instruction_signatures(&self) -> u64 {
match self {
Self::SimpleVote { .. } => 0,
Self::Transaction(usage_cost) => usage_cost.num_ed25519_instruction_signatures,
}
}
}

const MAX_WRITABLE_ACCOUNTS: usize = 256;
Expand All @@ -113,6 +134,9 @@ pub struct UsageCostDetails {
pub bpf_execution_cost: u64,
pub loaded_accounts_data_size_cost: u64,
pub account_data_size: u64,
pub num_transaction_signatures: u64,
pub num_secp256k1_instruction_signatures: u64,
pub num_ed25519_instruction_signatures: u64,
}

impl Default for UsageCostDetails {
Expand All @@ -126,6 +150,9 @@ impl Default for UsageCostDetails {
bpf_execution_cost: 0u64,
loaded_accounts_data_size_cost: 0u64,
account_data_size: 0u64,
num_transaction_signatures: 0u64,
num_secp256k1_instruction_signatures: 0u64,
num_ed25519_instruction_signatures: 0u64,
}
}
}
Expand All @@ -144,6 +171,10 @@ impl PartialEq for UsageCostDetails {
&& self.bpf_execution_cost == other.bpf_execution_cost
&& self.loaded_accounts_data_size_cost == other.loaded_accounts_data_size_cost
&& self.account_data_size == other.account_data_size
&& self.num_transaction_signatures == other.num_transaction_signatures
&& self.num_secp256k1_instruction_signatures
== other.num_secp256k1_instruction_signatures
&& self.num_ed25519_instruction_signatures == other.num_ed25519_instruction_signatures
&& to_hash_set(&self.writable_accounts) == to_hash_set(&other.writable_accounts)
}
}
Expand Down
116 changes: 105 additions & 11 deletions sdk/program/src/message/sanitized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,17 +345,7 @@ impl SanitizedMessage {
}

pub fn num_signatures(&self) -> u64 {
let mut num_signatures = u64::from(self.header().num_required_signatures);
// This next part is really calculating the number of pre-processor
// operations being done and treating them like a signature
for (program_id, instruction) in self.program_instructions_iter() {
if secp256k1_program::check_id(program_id) || ed25519_program::check_id(program_id) {
if let Some(num_verifies) = instruction.data.first() {
num_signatures = num_signatures.saturating_add(u64::from(*num_verifies));
}
}
}
num_signatures
self.get_signature_details().total_signatures()
}

/// Returns the number of requested write-locks in this message.
Expand All @@ -365,6 +355,68 @@ impl SanitizedMessage {
.len()
.saturating_sub(self.num_readonly_accounts()) as u64
}

/// return detailed signature counts
pub fn get_signature_details(&self) -> TransactionSignatureDetails {
let mut transaction_signature_details = TransactionSignatureDetails {
num_transaction_signatures: u64::from(self.header().num_required_signatures),
..TransactionSignatureDetails::default()
};

// counting the number of pre-processor operations separately
for (program_id, instruction) in self.program_instructions_iter() {
if secp256k1_program::check_id(program_id) {
if let Some(num_verifies) = instruction.data.first() {
transaction_signature_details.num_secp256k1_instruction_signatures =
transaction_signature_details
.num_secp256k1_instruction_signatures
.saturating_add(u64::from(*num_verifies));
}
} else if ed25519_program::check_id(program_id) {
if let Some(num_verifies) = instruction.data.first() {
transaction_signature_details.num_ed25519_instruction_signatures =
transaction_signature_details
.num_ed25519_instruction_signatures
.saturating_add(u64::from(*num_verifies));
}
}
}

transaction_signature_details
}
}

#[derive(Default)]
/// Transaction signature details including the number of transaction signatures
/// and precompile signatures.
pub struct TransactionSignatureDetails {
num_transaction_signatures: u64,
num_secp256k1_instruction_signatures: u64,
num_ed25519_instruction_signatures: u64,
}

impl TransactionSignatureDetails {
/// return total number of signature, treating pre-processor operations as signature
pub(crate) fn total_signatures(&self) -> u64 {
self.num_transaction_signatures
.saturating_add(self.num_secp256k1_instruction_signatures)
.saturating_add(self.num_ed25519_instruction_signatures)
}

/// return the number of transaction signatures
pub fn num_transaction_signatures(&self) -> u64 {
self.num_transaction_signatures
}

/// return the number of secp256k1 instruction signatures
pub fn num_secp256k1_instruction_signatures(&self) -> u64 {
self.num_secp256k1_instruction_signatures
}

/// return the number of ed25519 instruction signatures
pub fn num_ed25519_instruction_signatures(&self) -> u64 {
self.num_ed25519_instruction_signatures
}
}

#[cfg(test)]
Expand Down Expand Up @@ -563,4 +615,46 @@ mod tests {
}
}
}

#[test]
fn test_get_signature_details() {
let key0 = Pubkey::new_unique();
let key1 = Pubkey::new_unique();
let loader_key = Pubkey::new_unique();

let loader_instr = CompiledInstruction::new(2, &(), vec![0, 1]);
let mock_secp256k1_instr = CompiledInstruction::new(3, &[1u8; 10], vec![]);
let mock_ed25519_instr = CompiledInstruction::new(4, &[5u8; 10], vec![]);

let message = SanitizedMessage::try_from_legacy_message(
legacy::Message::new_with_compiled_instructions(
2,
1,
2,
vec![
key0,
key1,
loader_key,
secp256k1_program::id(),
ed25519_program::id(),
],
Hash::default(),
vec![
loader_instr,
mock_secp256k1_instr.clone(),
mock_ed25519_instr,
mock_secp256k1_instr,
],
),
)
.unwrap();

let signature_details = message.get_signature_details();
// expect 2 required transaction signatures
assert_eq!(2, signature_details.num_transaction_signatures);
// expect 2 secp256k1 instruction signatures - 1 for each mock_secp2561k1_instr
assert_eq!(2, signature_details.num_secp256k1_instruction_signatures);
// expect 5 ed25519 instruction signatures from mock_ed25519_instr
assert_eq!(5, signature_details.num_ed25519_instruction_signatures);
}
}
Loading