solana_account_decoder/
parse_address_lookup_table.rs1use {
2 crate::parse_account_data::{ParsableAccount, ParseAccountError},
3 solana_sdk::{address_lookup_table::state::AddressLookupTable, instruction::InstructionError},
4};
5
6pub fn parse_address_lookup_table(
7 data: &[u8],
8) -> Result<LookupTableAccountType, ParseAccountError> {
9 AddressLookupTable::deserialize(data)
10 .map(|address_lookup_table| {
11 LookupTableAccountType::LookupTable(address_lookup_table.into())
12 })
13 .or_else(|err| match err {
14 InstructionError::UninitializedAccount => Ok(LookupTableAccountType::Uninitialized),
15 _ => Err(ParseAccountError::AccountNotParsable(
16 ParsableAccount::AddressLookupTable,
17 )),
18 })
19}
20
21#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
22#[serde(rename_all = "camelCase", tag = "type", content = "info")]
23pub enum LookupTableAccountType {
24 Uninitialized,
25 LookupTable(UiLookupTable),
26}
27
28#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
29#[serde(rename_all = "camelCase")]
30pub struct UiLookupTable {
31 pub deactivation_slot: String,
32 pub last_extended_slot: String,
33 pub last_extended_slot_start_index: u8,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub authority: Option<String>,
36 pub addresses: Vec<String>,
37}
38
39impl<'a> From<AddressLookupTable<'a>> for UiLookupTable {
40 fn from(address_lookup_table: AddressLookupTable) -> Self {
41 Self {
42 deactivation_slot: address_lookup_table.meta.deactivation_slot.to_string(),
43 last_extended_slot: address_lookup_table.meta.last_extended_slot.to_string(),
44 last_extended_slot_start_index: address_lookup_table
45 .meta
46 .last_extended_slot_start_index,
47 authority: address_lookup_table
48 .meta
49 .authority
50 .map(|authority| authority.to_string()),
51 addresses: address_lookup_table
52 .addresses
53 .iter()
54 .map(|address| address.to_string())
55 .collect(),
56 }
57 }
58}
59
60#[cfg(test)]
61mod test {
62 use {
63 super::*,
64 solana_sdk::{
65 address_lookup_table::state::{LookupTableMeta, LOOKUP_TABLE_META_SIZE},
66 pubkey::Pubkey,
67 },
68 std::borrow::Cow,
69 };
70
71 #[test]
72 fn test_parse_address_lookup_table() {
73 let authority = Pubkey::new_unique();
74 let deactivation_slot = 1;
75 let last_extended_slot = 2;
76 let last_extended_slot_start_index = 3;
77 let lookup_table_meta = LookupTableMeta {
78 deactivation_slot,
79 last_extended_slot,
80 last_extended_slot_start_index,
81 authority: Some(authority),
82 ..LookupTableMeta::default()
83 };
84 let num_addresses = 42;
85 let mut addresses = Vec::with_capacity(num_addresses);
86 addresses.resize_with(num_addresses, Pubkey::new_unique);
87 let lookup_table = AddressLookupTable {
88 meta: lookup_table_meta,
89 addresses: Cow::Owned(addresses),
90 };
91 let lookup_table_data = AddressLookupTable::serialize_for_tests(lookup_table).unwrap();
92
93 let parsing_result = parse_address_lookup_table(&lookup_table_data).unwrap();
94 if let LookupTableAccountType::LookupTable(ui_lookup_table) = parsing_result {
95 assert_eq!(
96 ui_lookup_table.deactivation_slot,
97 deactivation_slot.to_string()
98 );
99 assert_eq!(
100 ui_lookup_table.last_extended_slot,
101 last_extended_slot.to_string()
102 );
103 assert_eq!(
104 ui_lookup_table.last_extended_slot_start_index,
105 last_extended_slot_start_index
106 );
107 assert_eq!(ui_lookup_table.authority, Some(authority.to_string()));
108 assert_eq!(ui_lookup_table.addresses.len(), num_addresses);
109 }
110
111 assert_eq!(
112 parse_address_lookup_table(&[0u8; LOOKUP_TABLE_META_SIZE]).unwrap(),
113 LookupTableAccountType::Uninitialized
114 );
115 assert!(parse_address_lookup_table(&[]).is_err());
116 }
117}