solana_block_decoder/address/
loaded_addresses.rs

1use {
2    solana_pubkey::{
3        Pubkey,
4        ParsePubkeyError,
5    },
6    solana_transaction_status_client_types::{
7        UiLoadedAddresses,
8    },
9    serde::{
10        Deserialize, Serialize,
11    },
12    std::{
13        str::FromStr,
14    },
15    log::{debug},
16};
17
18/// Collection of addresses loaded from on-chain lookup tables, split
19/// by readonly and writable.
20#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
21pub struct LoadedAddresses {
22    /// List of addresses for writable loaded accounts
23    pub writable: Vec<Pubkey>,
24    /// List of addresses for read-only loaded accounts
25    pub readonly: Vec<Pubkey>,
26}
27
28impl TryFrom<&UiLoadedAddresses> for LoadedAddresses {
29    type Error = ParsePubkeyError;
30
31    fn try_from(ui_loaded_addresses: &UiLoadedAddresses) -> Result<Self, Self::Error> {
32        let writable: Result<Vec<Pubkey>, _> = ui_loaded_addresses
33            .writable
34            .iter()
35            .map(|s| {
36                debug!("Parsing writable pubkey: {}", s); // Debugging
37                Pubkey::from_str(s)
38            })
39            .collect();
40
41        let readonly: Result<Vec<Pubkey>, _> = ui_loaded_addresses
42            .readonly
43            .iter()
44            .map(|s| {
45                debug!("Parsing readonly pubkey: {}", s); // Debugging
46                Pubkey::from_str(s)
47            })
48            .collect();
49
50        Ok(Self {
51            writable: writable?,
52            readonly: readonly?,
53        })
54    }
55}
56
57impl From<LoadedAddresses> for solana_message::v0::LoadedAddresses {
58    fn from(addresses: LoadedAddresses) -> Self {
59        Self {
60            writable: addresses.writable,
61            readonly: addresses.readonly,
62        }
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use solana_pubkey::Pubkey;
70    use solana_transaction_status_client_types::UiLoadedAddresses;
71    use std::str::FromStr;
72
73    #[test]
74    fn test_loaded_addresses_try_from_valid_ui_loaded_addresses() {
75        let ui_loaded_addresses = UiLoadedAddresses {
76            writable: vec![
77                "11111111111111111111111111111111".to_string(),
78                "22222222222222222222222222222222".to_string(),
79            ],
80            readonly: vec![
81                "33333333333333333333333333333333".to_string(),
82                "44444444444444444444444444444444".to_string(),
83            ],
84        };
85
86        let loaded_addresses = LoadedAddresses::try_from(&ui_loaded_addresses);
87        assert!(loaded_addresses.is_err(), "Expected error due to invalid base58 encoding");
88    }
89
90    #[test]
91    fn test_loaded_addresses_try_from_invalid_ui_loaded_addresses() {
92        let ui_loaded_addresses = UiLoadedAddresses {
93            writable: vec!["invalid_pubkey".to_string()],
94            readonly: vec!["44444444444444444444444444444444".to_string()],
95        };
96
97        let result = LoadedAddresses::try_from(&ui_loaded_addresses);
98        assert!(result.is_err());
99    }
100
101    #[test]
102    fn test_loaded_addresses_try_from_empty_ui_loaded_addresses() {
103        let ui_loaded_addresses = UiLoadedAddresses {
104            writable: vec![],
105            readonly: vec![],
106        };
107
108        let loaded_addresses = LoadedAddresses::try_from(&ui_loaded_addresses).unwrap();
109
110        assert!(loaded_addresses.writable.is_empty());
111        assert!(loaded_addresses.readonly.is_empty());
112    }
113
114    #[test]
115    fn test_loaded_addresses_into_solana_message_loaded_addresses() {
116        let loaded_addresses = LoadedAddresses {
117            writable: vec![Pubkey::new_unique()],
118            readonly: vec![Pubkey::new_unique()],
119        };
120
121        let solana_loaded_addresses: solana_message::v0::LoadedAddresses = loaded_addresses.clone().into();
122
123        assert_eq!(solana_loaded_addresses.writable, loaded_addresses.writable);
124        assert_eq!(solana_loaded_addresses.readonly, loaded_addresses.readonly);
125    }
126
127    #[test]
128    fn test_loaded_addresses_try_from_ui_loaded_addresses_with_correct_pubkeys() {
129        let ui_loaded_addresses = UiLoadedAddresses {
130            writable: vec![Pubkey::new_unique().to_string()],
131            readonly: vec![Pubkey::new_unique().to_string()],
132        };
133
134        let result = LoadedAddresses::try_from(&ui_loaded_addresses);
135        assert!(result.is_ok(), "Expected successful conversion");
136    }
137
138    #[test]
139    fn test_loaded_addresses_try_from_ui_loaded_addresses_with_wrong_size_writable_pubkeys() {
140        let ui_loaded_addresses = UiLoadedAddresses {
141            writable: vec!["12345".to_string()],
142            readonly: vec![Pubkey::new_unique().to_string()],
143        };
144
145        let result = LoadedAddresses::try_from(&ui_loaded_addresses);
146        assert!(result.is_err(), "Expected an error due to incorrect pubkey size");
147    }
148
149    #[test]
150    fn test_loaded_addresses_try_from_ui_loaded_addresses_with_wrong_size_readonly_pubkeys() {
151        let ui_loaded_addresses = UiLoadedAddresses {
152            writable: vec![Pubkey::new_unique().to_string()],
153            readonly: vec!["67890".to_string()],
154        };
155
156        let result = LoadedAddresses::try_from(&ui_loaded_addresses);
157        assert!(result.is_err(), "Expected an error due to incorrect readonly pubkey size");
158    }
159}
160
161