solana_transaction/versioned/
sanitized.rs

1use {
2    crate::versioned::VersionedTransaction, solana_message::SanitizedVersionedMessage,
3    solana_sanitize::SanitizeError, solana_signature::Signature,
4};
5
6/// Wraps a sanitized `VersionedTransaction` to provide a safe API
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct SanitizedVersionedTransaction {
9    /// List of signatures
10    pub(crate) signatures: Vec<Signature>,
11    /// Message to sign.
12    pub(crate) message: SanitizedVersionedMessage,
13}
14
15impl TryFrom<VersionedTransaction> for SanitizedVersionedTransaction {
16    type Error = SanitizeError;
17    fn try_from(tx: VersionedTransaction) -> Result<Self, Self::Error> {
18        Self::try_new(tx)
19    }
20}
21
22impl SanitizedVersionedTransaction {
23    pub fn try_new(tx: VersionedTransaction) -> Result<Self, SanitizeError> {
24        tx.sanitize_signatures()?;
25        Ok(Self {
26            signatures: tx.signatures,
27            message: SanitizedVersionedMessage::try_from(tx.message)?,
28        })
29    }
30
31    pub fn get_message(&self) -> &SanitizedVersionedMessage {
32        &self.message
33    }
34
35    /// Consumes the SanitizedVersionedTransaction, returning the fields individually.
36    pub fn destruct(self) -> (Vec<Signature>, SanitizedVersionedMessage) {
37        (self.signatures, self.message)
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use {
44        super::*,
45        solana_hash::Hash,
46        solana_message::{v0, VersionedMessage},
47        solana_pubkey::Pubkey,
48    };
49
50    #[test]
51    fn test_try_new_with_invalid_signatures() {
52        let tx = VersionedTransaction {
53            signatures: vec![],
54            message: VersionedMessage::V0(
55                v0::Message::try_compile(&Pubkey::new_unique(), &[], &[], Hash::default()).unwrap(),
56            ),
57        };
58
59        assert_eq!(
60            SanitizedVersionedTransaction::try_new(tx),
61            Err(SanitizeError::IndexOutOfBounds)
62        );
63    }
64
65    #[test]
66    fn test_try_new() {
67        let mut message =
68            v0::Message::try_compile(&Pubkey::new_unique(), &[], &[], Hash::default()).unwrap();
69        message.header.num_readonly_signed_accounts += 1;
70
71        let tx = VersionedTransaction {
72            signatures: vec![Signature::default()],
73            message: VersionedMessage::V0(message),
74        };
75
76        assert_eq!(
77            SanitizedVersionedTransaction::try_new(tx),
78            Err(SanitizeError::InvalidValue)
79        );
80    }
81}