use {
crate::{
bytes::{advance_offset_for_array, read_byte},
result::{Result, TransactionViewError},
},
solana_packet::PACKET_DATA_SIZE,
solana_pubkey::Pubkey,
solana_signature::Signature,
};
const MAX_SIGNATURES_PER_PACKET: u8 =
(PACKET_DATA_SIZE / (core::mem::size_of::<Signature>() + core::mem::size_of::<Pubkey>())) as u8;
#[derive(Debug)]
pub(crate) struct SignatureFrame {
pub(crate) num_signatures: u8,
pub(crate) offset: u16,
}
impl SignatureFrame {
#[inline(always)]
pub(crate) fn try_new(bytes: &[u8], offset: &mut usize) -> Result<Self> {
const _: () = assert!(MAX_SIGNATURES_PER_PACKET & 0b1000_0000 == 0);
let num_signatures = read_byte(bytes, offset)?;
if num_signatures == 0 || num_signatures > MAX_SIGNATURES_PER_PACKET {
return Err(TransactionViewError::ParseError);
}
let signature_offset = *offset as u16;
advance_offset_for_array::<Signature>(bytes, offset, u16::from(num_signatures))?;
Ok(Self {
num_signatures,
offset: signature_offset,
})
}
}
#[cfg(test)]
mod tests {
use {super::*, solana_short_vec::ShortVec};
#[test]
fn test_zero_signatures() {
let bytes = bincode::serialize(&ShortVec(Vec::<Signature>::new())).unwrap();
let mut offset = 0;
assert!(SignatureFrame::try_new(&bytes, &mut offset).is_err());
}
#[test]
fn test_one_signature() {
let bytes = bincode::serialize(&ShortVec(vec![Signature::default()])).unwrap();
let mut offset = 0;
let frame = SignatureFrame::try_new(&bytes, &mut offset).unwrap();
assert_eq!(frame.num_signatures, 1);
assert_eq!(frame.offset, 1);
assert_eq!(offset, 1 + core::mem::size_of::<Signature>());
}
#[test]
fn test_max_signatures() {
let signatures = vec![Signature::default(); usize::from(MAX_SIGNATURES_PER_PACKET)];
let bytes = bincode::serialize(&ShortVec(signatures)).unwrap();
let mut offset = 0;
let frame = SignatureFrame::try_new(&bytes, &mut offset).unwrap();
assert_eq!(frame.num_signatures, 12);
assert_eq!(frame.offset, 1);
assert_eq!(offset, 1 + 12 * core::mem::size_of::<Signature>());
}
#[test]
fn test_non_zero_offset() {
let mut bytes = bincode::serialize(&ShortVec(vec![Signature::default()])).unwrap();
bytes.insert(0, 0); let mut offset = 1; let frame = SignatureFrame::try_new(&bytes, &mut offset).unwrap();
assert_eq!(frame.num_signatures, 1);
assert_eq!(frame.offset, 2);
assert_eq!(offset, 2 + core::mem::size_of::<Signature>());
}
#[test]
fn test_too_many_signatures() {
let signatures = vec![Signature::default(); usize::from(MAX_SIGNATURES_PER_PACKET) + 1];
let bytes = bincode::serialize(&ShortVec(signatures)).unwrap();
let mut offset = 0;
assert!(SignatureFrame::try_new(&bytes, &mut offset).is_err());
}
#[test]
fn test_u16_max_signatures() {
let signatures = vec![Signature::default(); u16::MAX as usize];
let bytes = bincode::serialize(&ShortVec(signatures)).unwrap();
let mut offset = 0;
assert!(SignatureFrame::try_new(&bytes, &mut offset).is_err());
}
}