add precompile signature metrics to cost tracker (#133)
This commit is contained in:
parent
9decf2a320
commit
ca41b16e47
|
@ -24,6 +24,10 @@ pub const MAX_CONCURRENCY: u64 = 4;
|
||||||
pub const COMPUTE_UNIT_TO_US_RATIO: u64 = 30;
|
pub const COMPUTE_UNIT_TO_US_RATIO: u64 = 30;
|
||||||
/// Number of compute units for one signature verification.
|
/// Number of compute units for one signature verification.
|
||||||
pub const SIGNATURE_COST: u64 = COMPUTE_UNIT_TO_US_RATIO * 24;
|
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
|
/// Number of compute units for one write lock
|
||||||
pub const WRITE_LOCK_UNITS: u64 = COMPUTE_UNIT_TO_US_RATIO * 10;
|
pub const WRITE_LOCK_UNITS: u64 = COMPUTE_UNIT_TO_US_RATIO * 10;
|
||||||
/// Number of data bytes per compute units
|
/// Number of data bytes per compute units
|
||||||
|
@ -43,8 +47,8 @@ lazy_static! {
|
||||||
(bpf_loader::id(), solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS),
|
(bpf_loader::id(), solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS),
|
||||||
(loader_v4::id(), solana_loader_v4_program::DEFAULT_COMPUTE_UNITS),
|
(loader_v4::id(), solana_loader_v4_program::DEFAULT_COMPUTE_UNITS),
|
||||||
// Note: These are precompile, run directly in bank during sanitizing;
|
// Note: These are precompile, run directly in bank during sanitizing;
|
||||||
(secp256k1_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24),
|
(secp256k1_program::id(), 0),
|
||||||
(ed25519_program::id(), COMPUTE_UNIT_TO_US_RATIO * 24),
|
(ed25519_program::id(), 0),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl CostModel {
|
||||||
} else {
|
} else {
|
||||||
let mut tx_cost = UsageCostDetails::new_with_default_capacity();
|
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_write_lock_cost(&mut tx_cost, transaction, feature_set);
|
||||||
Self::get_transaction_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);
|
tx_cost.account_data_size = Self::calculate_account_data_size(transaction);
|
||||||
|
@ -53,8 +53,26 @@ impl CostModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_signature_cost(transaction: &SanitizedTransaction) -> u64 {
|
fn get_signature_cost(tx_cost: &mut UsageCostDetails, transaction: &SanitizedTransaction) {
|
||||||
transaction.signatures().len() as u64 * SIGNATURE_COST
|
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> {
|
fn get_writable_accounts(transaction: &SanitizedTransaction) -> Vec<Pubkey> {
|
||||||
|
|
|
@ -58,6 +58,9 @@ pub struct CostTracker {
|
||||||
vote_cost: u64,
|
vote_cost: u64,
|
||||||
transaction_count: u64,
|
transaction_count: u64,
|
||||||
account_data_size: u64,
|
account_data_size: u64,
|
||||||
|
transaction_signature_count: u64,
|
||||||
|
secp256k1_instruction_signature_count: u64,
|
||||||
|
ed25519_instruction_signature_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CostTracker {
|
impl Default for CostTracker {
|
||||||
|
@ -77,6 +80,9 @@ impl Default for CostTracker {
|
||||||
vote_cost: 0,
|
vote_cost: 0,
|
||||||
transaction_count: 0,
|
transaction_count: 0,
|
||||||
account_data_size: 0,
|
account_data_size: 0,
|
||||||
|
transaction_signature_count: 0,
|
||||||
|
secp256k1_instruction_signature_count: 0,
|
||||||
|
ed25519_instruction_signature_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +159,21 @@ impl CostTracker {
|
||||||
("costliest_account", costliest_account.to_string(), String),
|
("costliest_account", costliest_account.to_string(), String),
|
||||||
("costliest_account_cost", costliest_account_cost as i64, i64),
|
("costliest_account_cost", costliest_account_cost as i64, i64),
|
||||||
("account_data_size", self.account_data_size, 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
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +234,18 @@ impl CostTracker {
|
||||||
self.add_transaction_execution_cost(tx_cost, tx_cost.sum());
|
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.account_data_size, tx_cost.account_data_size());
|
||||||
saturating_add_assign!(self.transaction_count, 1);
|
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) {
|
fn remove_transaction_cost(&mut self, tx_cost: &TransactionCost) {
|
||||||
|
@ -222,6 +255,15 @@ impl CostTracker {
|
||||||
.account_data_size
|
.account_data_size
|
||||||
.saturating_sub(tx_cost.account_data_size());
|
.saturating_sub(tx_cost.account_data_size());
|
||||||
self.transaction_count = self.transaction_count.saturating_sub(1);
|
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
|
/// Apply additional actual execution units to cost_tracker
|
||||||
|
|
|
@ -91,6 +91,27 @@ impl TransactionCost {
|
||||||
Self::Transaction(usage_cost) => &usage_cost.writable_accounts,
|
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;
|
const MAX_WRITABLE_ACCOUNTS: usize = 256;
|
||||||
|
@ -105,6 +126,9 @@ pub struct UsageCostDetails {
|
||||||
pub programs_execution_cost: u64,
|
pub programs_execution_cost: u64,
|
||||||
pub loaded_accounts_data_size_cost: u64,
|
pub loaded_accounts_data_size_cost: u64,
|
||||||
pub account_data_size: 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 {
|
impl Default for UsageCostDetails {
|
||||||
|
@ -117,6 +141,9 @@ impl Default for UsageCostDetails {
|
||||||
programs_execution_cost: 0u64,
|
programs_execution_cost: 0u64,
|
||||||
loaded_accounts_data_size_cost: 0u64,
|
loaded_accounts_data_size_cost: 0u64,
|
||||||
account_data_size: 0u64,
|
account_data_size: 0u64,
|
||||||
|
num_transaction_signatures: 0u64,
|
||||||
|
num_secp256k1_instruction_signatures: 0u64,
|
||||||
|
num_ed25519_instruction_signatures: 0u64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +161,10 @@ impl PartialEq for UsageCostDetails {
|
||||||
&& self.programs_execution_cost == other.programs_execution_cost
|
&& self.programs_execution_cost == other.programs_execution_cost
|
||||||
&& self.loaded_accounts_data_size_cost == other.loaded_accounts_data_size_cost
|
&& self.loaded_accounts_data_size_cost == other.loaded_accounts_data_size_cost
|
||||||
&& self.account_data_size == other.account_data_size
|
&& 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)
|
&& to_hash_set(&self.writable_accounts) == to_hash_set(&other.writable_accounts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,17 +345,7 @@ impl SanitizedMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_signatures(&self) -> u64 {
|
pub fn num_signatures(&self) -> u64 {
|
||||||
let mut num_signatures = u64::from(self.header().num_required_signatures);
|
self.get_signature_details().total_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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of requested write-locks in this message.
|
/// Returns the number of requested write-locks in this message.
|
||||||
|
@ -365,6 +355,68 @@ impl SanitizedMessage {
|
||||||
.len()
|
.len()
|
||||||
.saturating_sub(self.num_readonly_accounts()) as u64
|
.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)]
|
#[cfg(test)]
|
||||||
|
@ -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…
Reference in New Issue