sq: optimize

This commit is contained in:
Trent Nelson 2021-03-19 22:12:58 -06:00 committed by Trent Nelson
parent 834fae684b
commit 482c027d3b
2 changed files with 62 additions and 60 deletions

View File

@ -8,11 +8,10 @@ use crate::cuda_runtime::PinnedVec;
use crate::packet::{Packet, Packets}; use crate::packet::{Packet, Packets};
use crate::perf_libs; use crate::perf_libs;
use crate::recycler::Recycler; use crate::recycler::Recycler;
use bincode::serialized_size;
use rayon::ThreadPool; use rayon::ThreadPool;
use solana_metrics::inc_new_counter_debug; use solana_metrics::inc_new_counter_debug;
use solana_rayon_threadlimit::get_thread_count; use solana_rayon_threadlimit::get_thread_count;
use solana_sdk::message::MessageHeader; use solana_sdk::message::MESSAGE_HEADER_LENGTH;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::short_vec::decode_len; use solana_sdk::short_vec::decode_len;
use solana_sdk::signature::Signature; use solana_sdk::signature::Signature;
@ -75,6 +74,12 @@ impl std::convert::From<std::boxed::Box<bincode::ErrorKind>> for PacketError {
} }
} }
impl std::convert::From<std::num::TryFromIntError> for PacketError {
fn from(_e: std::num::TryFromIntError) -> Self {
Self::InvalidLen
}
}
pub fn init() { pub fn init() {
if let Some(api) = perf_libs::api() { if let Some(api) = perf_libs::api() {
unsafe { unsafe {
@ -147,17 +152,14 @@ pub fn batch_size(batches: &[Packets]) -> usize {
// internal function to be unit-tested; should be used only by get_packet_offsets // internal function to be unit-tested; should be used only by get_packet_offsets
fn do_get_packet_offsets( fn do_get_packet_offsets(
packet: &Packet, packet: &Packet,
current_offset: u32, current_offset: usize,
) -> Result<PacketOffsets, PacketError> { ) -> Result<PacketOffsets, PacketError> {
let message_header_size = serialized_size(&MessageHeader::default()).unwrap() as usize;
// should have at least 1 signature, sig lengths and the message header // should have at least 1 signature, sig lengths and the message header
let min_packet_size = 1usize let _ = 1usize
.checked_add(size_of::<Signature>()) .checked_add(size_of::<Signature>())
.and_then(|v| v.checked_add(message_header_size)) .and_then(|v| v.checked_add(MESSAGE_HEADER_LENGTH))
.filter(|v| *v <= packet.meta.size)
.ok_or(PacketError::InvalidLen)?; .ok_or(PacketError::InvalidLen)?;
if min_packet_size > packet.meta.size {
return Err(PacketError::InvalidLen);
}
// read the length of Transaction.signatures (serialized with short_vec) // read the length of Transaction.signatures (serialized with short_vec)
let (sig_len_untrusted, sig_size) = let (sig_len_untrusted, sig_size) =
@ -170,76 +172,69 @@ fn do_get_packet_offsets(
.and_then(|v| v.checked_add(sig_size)) .and_then(|v| v.checked_add(sig_size))
.ok_or(PacketError::InvalidLen)?; .ok_or(PacketError::InvalidLen)?;
let msg_start_offset_plus_one = msg_start_offset
.checked_add(1)
.ok_or(PacketError::InvalidLen)?;
// Packet should have data at least for signatures, MessageHeader, 1 byte for Message.account_keys.len // Packet should have data at least for signatures, MessageHeader, 1 byte for Message.account_keys.len
let min_message_end_offset = msg_start_offset let _ = msg_start_offset_plus_one
.checked_add(message_header_size) .checked_add(MESSAGE_HEADER_LENGTH)
.and_then(|v| v.checked_add(1)) .filter(|v| *v <= packet.meta.size)
.ok_or(PacketError::InvalidSignatureLen)?; .ok_or(PacketError::InvalidSignatureLen)?;
if min_message_end_offset > packet.meta.size {
return Err(PacketError::InvalidSignatureLen);
}
// read MessageHeader.num_required_signatures (serialized with u8) // read MessageHeader.num_required_signatures (serialized with u8)
let sig_len_maybe_trusted = packet.data[msg_start_offset] as usize; let sig_len_maybe_trusted = packet.data[msg_start_offset];
let message_account_keys_len_offset = msg_start_offset let message_account_keys_len_offset = msg_start_offset
.checked_add(message_header_size) .checked_add(MESSAGE_HEADER_LENGTH)
.ok_or(PacketError::InvalidLen)?; .ok_or(PacketError::InvalidLen)?;
// This reads and compares the MessageHeader num_required_signatures and // This reads and compares the MessageHeader num_required_signatures and
// num_readonly_signed_accounts bytes. If num_required_signatures is not larger than // num_readonly_signed_accounts bytes. If num_required_signatures is not larger than
// num_readonly_signed_accounts, the first account is not debitable, and cannot be charged // num_readonly_signed_accounts, the first account is not debitable, and cannot be charged
// required transaction fees. // required transaction fees.
let readonly_signer_offset = msg_start_offset let readonly_signer_offset = msg_start_offset_plus_one;
.checked_add(1) if sig_len_maybe_trusted <= packet.data[readonly_signer_offset] {
.ok_or(PacketError::InvalidLen)?;
if packet.data[msg_start_offset] <= packet.data[readonly_signer_offset] {
return Err(PacketError::PayerNotWritable); return Err(PacketError::PayerNotWritable);
} }
if usize::from(sig_len_maybe_trusted) != sig_len_untrusted {
return Err(PacketError::MismatchSignatureLen);
}
// read the length of Message.account_keys (serialized with short_vec) // read the length of Message.account_keys (serialized with short_vec)
let (pubkey_len, pubkey_len_size) = decode_len(&packet.data[message_account_keys_len_offset..]) let (pubkey_len, pubkey_len_size) = decode_len(&packet.data[message_account_keys_len_offset..])
.map_err(|_| PacketError::InvalidShortVec)?; .map_err(|_| PacketError::InvalidShortVec)?;
let min_account_keys_end_offset = pubkey_len let pubkey_start = message_account_keys_len_offset
.checked_mul(size_of::<Pubkey>()) .checked_add(pubkey_len_size)
.and_then(|v| v.checked_add(message_account_keys_len_offset))
.and_then(|v| v.checked_add(pubkey_len_size))
.ok_or(PacketError::InvalidPubkeyLen)?; .ok_or(PacketError::InvalidPubkeyLen)?;
if min_account_keys_end_offset > packet.meta.size {
return Err(PacketError::InvalidPubkeyLen);
}
let sig_start = usize::try_from(current_offset) let _ = pubkey_len
.ok() .checked_mul(size_of::<Pubkey>())
.and_then(|v| v.checked_add(sig_size)) .and_then(|v| v.checked_add(pubkey_start))
.ok_or(PacketError::InvalidLen)?; .filter(|v| *v <= packet.meta.size)
let msg_start = usize::try_from(current_offset) .ok_or(PacketError::InvalidPubkeyLen)?;
.ok()
.and_then(|v| v.checked_add(msg_start_offset))
.ok_or(PacketError::InvalidLen)?;
let pubkey_start = msg_start
.checked_add(message_header_size)
.and_then(|v| v.checked_add(pubkey_len_size))
.ok_or(PacketError::InvalidLen)?;
if sig_len_maybe_trusted != sig_len_untrusted { let sig_start = current_offset
return Err(PacketError::MismatchSignatureLen); .checked_add(sig_size)
} .ok_or(PacketError::InvalidLen)?;
let msg_start = current_offset
fn to_u32(value: usize) -> Result<u32, PacketError> { .checked_add(msg_start_offset)
u32::try_from(value).map_err(|_| PacketError::InvalidLen) .ok_or(PacketError::InvalidLen)?;
} let pubkey_start = current_offset
.checked_add(pubkey_start)
.ok_or(PacketError::InvalidLen)?;
Ok(PacketOffsets::new( Ok(PacketOffsets::new(
to_u32(sig_len_untrusted)?, u32::try_from(sig_len_untrusted)?,
to_u32(sig_start)?, u32::try_from(sig_start)?,
to_u32(msg_start)?, u32::try_from(msg_start)?,
to_u32(pubkey_start)?, u32::try_from(pubkey_start)?,
)) ))
} }
fn get_packet_offsets(packet: &Packet, current_offset: u32) -> PacketOffsets { fn get_packet_offsets(packet: &Packet, current_offset: usize) -> PacketOffsets {
let unsanitized_packet_offsets = do_get_packet_offsets(packet, current_offset); let unsanitized_packet_offsets = do_get_packet_offsets(packet, current_offset);
if let Ok(offsets) = unsanitized_packet_offsets { if let Ok(offsets) = unsanitized_packet_offsets {
offsets offsets
@ -259,13 +254,11 @@ pub fn generate_offsets(batches: &[Packets], recycler: &Recycler<TxOffset>) -> T
msg_start_offsets.set_pinnable(); msg_start_offsets.set_pinnable();
let mut msg_sizes: PinnedVec<_> = recycler.allocate().unwrap(); let mut msg_sizes: PinnedVec<_> = recycler.allocate().unwrap();
msg_sizes.set_pinnable(); msg_sizes.set_pinnable();
let mut current_packet: u32 = 0; let mut current_offset: usize = 0;
let mut v_sig_lens = Vec::new(); let mut v_sig_lens = Vec::new();
batches.iter().for_each(|p| { batches.iter().for_each(|p| {
let mut sig_lens = Vec::new(); let mut sig_lens = Vec::new();
p.packets.iter().for_each(|packet| { p.packets.iter().for_each(|packet| {
let current_offset = current_packet.saturating_mul(size_of::<Packet>() as u32);
let packet_offsets = get_packet_offsets(packet, current_offset); let packet_offsets = get_packet_offsets(packet, current_offset);
sig_lens.push(packet_offsets.sig_len); sig_lens.push(packet_offsets.sig_len);
@ -274,6 +267,7 @@ pub fn generate_offsets(batches: &[Packets], recycler: &Recycler<TxOffset>) -> T
let mut pubkey_offset = packet_offsets.pubkey_start; let mut pubkey_offset = packet_offsets.pubkey_start;
let mut sig_offset = packet_offsets.sig_start; let mut sig_offset = packet_offsets.sig_start;
let msg_size = current_offset.saturating_add(packet.meta.size) as u32;
for _ in 0..packet_offsets.sig_len { for _ in 0..packet_offsets.sig_len {
signature_offsets.push(sig_offset); signature_offsets.push(sig_offset);
sig_offset = sig_offset.saturating_add(size_of::<Signature>() as u32); sig_offset = sig_offset.saturating_add(size_of::<Signature>() as u32);
@ -283,12 +277,10 @@ pub fn generate_offsets(batches: &[Packets], recycler: &Recycler<TxOffset>) -> T
msg_start_offsets.push(packet_offsets.msg_start); msg_start_offsets.push(packet_offsets.msg_start);
let msg_size = current_offset let msg_size = msg_size.saturating_sub(packet_offsets.msg_start);
.saturating_add(packet.meta.size as u32)
.saturating_sub(packet_offsets.msg_start);
msg_sizes.push(msg_size); msg_sizes.push(msg_size);
} }
current_packet = current_packet.saturating_add(1); current_offset = current_offset.saturating_add(size_of::<Packet>());
}); });
v_sig_lens.push(sig_lens); v_sig_lens.push(sig_lens);
}); });
@ -689,7 +681,7 @@ mod tests {
// Just like get_packet_offsets, but not returning redundant information. // Just like get_packet_offsets, but not returning redundant information.
fn get_packet_offsets_from_tx(tx: Transaction, current_offset: u32) -> PacketOffsets { fn get_packet_offsets_from_tx(tx: Transaction, current_offset: u32) -> PacketOffsets {
let packet = sigverify::make_packet_from_transaction(tx); let packet = sigverify::make_packet_from_transaction(tx);
let packet_offsets = sigverify::get_packet_offsets(&packet, current_offset); let packet_offsets = sigverify::get_packet_offsets(&packet, current_offset as usize);
PacketOffsets::new( PacketOffsets::new(
packet_offsets.sig_len, packet_offsets.sig_len,
packet_offsets.sig_start - current_offset, packet_offsets.sig_start - current_offset,

View File

@ -142,6 +142,8 @@ fn get_program_ids(instructions: &[Instruction]) -> Vec<Pubkey> {
.collect() .collect()
} }
pub const MESSAGE_HEADER_LENGTH: usize = 3;
#[frozen_abi(digest = "BVC5RhetsNpheGipt5rUrkR6RDDUHtD5sCLK1UjymL4S")] #[frozen_abi(digest = "BVC5RhetsNpheGipt5rUrkR6RDDUHtD5sCLK1UjymL4S")]
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, AbiExample)] #[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, AbiExample)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -941,4 +943,12 @@ mod tests {
assert!(message.is_non_loader_key(&key1, 1)); assert!(message.is_non_loader_key(&key1, 1));
assert!(!message.is_non_loader_key(&loader2, 2)); assert!(!message.is_non_loader_key(&loader2, 2));
} }
#[test]
fn test_message_header_len_constant() {
assert_eq!(
bincode::serialized_size(&MessageHeader::default()).unwrap() as usize,
MESSAGE_HEADER_LENGTH
);
}
} }